update web
This commit is contained in:
84
web/src/lib.rs
Normal file
84
web/src/lib.rs
Normal file
@@ -0,0 +1,84 @@
|
||||
use gpui::*;
|
||||
use ui::{Root, v_flex};
|
||||
use universal_time::{
|
||||
Duration, Instant, MonotonicClock, SystemTime, WallClock, define_time_provider,
|
||||
};
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
struct CustomTimeProvider;
|
||||
|
||||
impl WallClock for CustomTimeProvider {
|
||||
fn system_time(&self) -> SystemTime {
|
||||
SystemTime::from_unix_duration(Duration::from_secs(0))
|
||||
}
|
||||
}
|
||||
|
||||
impl MonotonicClock for CustomTimeProvider {
|
||||
fn instant(&self) -> Instant {
|
||||
Instant::from_ticks(Duration::from_secs(0))
|
||||
}
|
||||
}
|
||||
|
||||
define_time_provider!(CustomTimeProvider);
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn run() -> Result<(), JsValue> {
|
||||
console_error_panic_hook::set_once();
|
||||
|
||||
// Initialize logging to browser console
|
||||
console_log::init_with_level(log::Level::Info).expect("Failed to initialize logger");
|
||||
|
||||
// Also initialize tracing for WASM
|
||||
tracing_wasm::set_as_global_default();
|
||||
|
||||
#[cfg(target_family = "wasm")]
|
||||
gpui_platform::web_init();
|
||||
#[cfg(not(target_family = "wasm"))]
|
||||
let app = gpui_platform::application();
|
||||
#[cfg(target_family = "wasm")]
|
||||
let app = {
|
||||
let app = gpui_platform::single_threaded_web();
|
||||
// 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) }
|
||||
};
|
||||
|
||||
app.run(|cx| {
|
||||
// Initialize components
|
||||
ui::init(cx);
|
||||
|
||||
// Initialize theme registry
|
||||
theme::init(cx);
|
||||
|
||||
// Open the root window
|
||||
cx.open_window(WindowOptions::default(), |window, cx| {
|
||||
let view = cx.new(HelloWeb::new);
|
||||
cx.new(|cx| Root::new(view.into(), window, cx))
|
||||
})
|
||||
.expect("Failed to open window. Please restart the application.");
|
||||
|
||||
cx.activate(true);
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
struct HelloWeb {}
|
||||
|
||||
impl HelloWeb {
|
||||
fn new(_cx: &mut Context<Self>) -> Self {
|
||||
Self {}
|
||||
}
|
||||
}
|
||||
|
||||
impl Render for HelloWeb {
|
||||
fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
|
||||
v_flex()
|
||||
.size_full()
|
||||
.items_center()
|
||||
.justify_center()
|
||||
.child("Hello web")
|
||||
}
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
use gpui::*;
|
||||
use ui::Root;
|
||||
use universal_time::{
|
||||
Duration, Instant, MonotonicClock, SystemTime, WallClock, define_time_provider,
|
||||
};
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
struct CustomTimeProvider;
|
||||
|
||||
impl WallClock for CustomTimeProvider {
|
||||
fn system_time(&self) -> SystemTime {
|
||||
SystemTime::from_unix_duration(Duration::from_secs(0))
|
||||
}
|
||||
}
|
||||
|
||||
impl MonotonicClock for CustomTimeProvider {
|
||||
fn instant(&self) -> Instant {
|
||||
Instant::from_ticks(Duration::from_secs(0))
|
||||
}
|
||||
}
|
||||
|
||||
define_time_provider!(CustomTimeProvider);
|
||||
|
||||
fn main() {
|
||||
// Binary entry point, actual initialization happens in `run()` below,
|
||||
// which is called explicitly from JavaScript after the WASM module loads.
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn run() -> Result<(), JsValue> {
|
||||
console_error_panic_hook::set_once();
|
||||
|
||||
// Initialize logging to browser console
|
||||
console_log::init_with_level(log::Level::Info).expect("Failed to initialize logger");
|
||||
|
||||
// Also initialize tracing for WASM
|
||||
tracing_wasm::set_as_global_default();
|
||||
|
||||
#[cfg(target_family = "wasm")]
|
||||
gpui_platform::web_init();
|
||||
|
||||
gpui_platform::application().run(|cx| {
|
||||
cx.open_window(WindowOptions::default(), |window, cx| {
|
||||
cx.new(|cx| {
|
||||
// Initialize components
|
||||
ui::init(cx);
|
||||
|
||||
// Initialize theme registry
|
||||
theme::init(cx);
|
||||
|
||||
// Initialize settings
|
||||
settings::init(window, cx);
|
||||
|
||||
// Initialize the nostr client
|
||||
state::init(window, cx);
|
||||
|
||||
// Initialize person registry
|
||||
person::init(window, cx);
|
||||
|
||||
// Initialize device signer
|
||||
//
|
||||
// NIP-4e: https://github.com/nostr-protocol/nips/blob/per-device-keys/4e.md
|
||||
device::init(window, cx);
|
||||
|
||||
// Initialize app registry
|
||||
chat::init(window, cx);
|
||||
|
||||
// Root Entity
|
||||
Root::new(workspace::init(window, cx).into(), window, cx)
|
||||
})
|
||||
})
|
||||
.expect("Failed to open window. Please restart the application.");
|
||||
cx.activate(true);
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Coop</title>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family:
|
||||
-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
|
||||
Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue",
|
||||
sans-serif;
|
||||
overflow: hidden;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
#app {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#canvas {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#loading {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.spinner {
|
||||
border: 4px solid rgba(0, 0, 0, 0.1);
|
||||
border-left-color: #000;
|
||||
border-radius: 50%;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
animation: spin 1s linear infinite;
|
||||
margin: 0 auto 16px;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
.error {
|
||||
color: #d32f2f;
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app">
|
||||
<canvas id="canvas"></canvas>
|
||||
<div id="loading">
|
||||
<div class="spinner"></div>
|
||||
<p>Loading Coop...</p>
|
||||
</div>
|
||||
</div>
|
||||
<script type="module" src="main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,35 +0,0 @@
|
||||
async function init() {
|
||||
const loadingEl = document.getElementById('loading');
|
||||
const appEl = document.getElementById('app');
|
||||
|
||||
try {
|
||||
// Import the WASM module
|
||||
const wasm = await import('./wasm/coop_web.js');
|
||||
await wasm.default();
|
||||
|
||||
// Initialize the story gallery
|
||||
await wasm.run();
|
||||
|
||||
// Hide loading indicator
|
||||
if (appEl) {
|
||||
appEl.remove();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to initialize:', error);
|
||||
|
||||
// Show error message
|
||||
if (loadingEl) {
|
||||
loadingEl.innerHTML = `
|
||||
<div class="error">
|
||||
<h2>Failed to load the application</h2>
|
||||
<p>${error.message || error}</p>
|
||||
<p style="margin-top: 10px; font-size: 14px;">
|
||||
Please check the console for more details.
|
||||
</p>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
init();
|
||||
@@ -1,17 +0,0 @@
|
||||
{
|
||||
"name": "coop-web",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview",
|
||||
"wasm": "cargo build --target wasm32-unknown-unknown --release && wasm-bindgen ../../../target/wasm32-unknown-unknown/release/gpui_component_story_web.wasm --out-dir ./src/wasm --target web --no-typescript"
|
||||
},
|
||||
"devDependencies": {
|
||||
"vite": "^8",
|
||||
"vite-plugin-static-copy": "^3.2.0",
|
||||
"vite-plugin-wasm": "^3.3.0"
|
||||
}
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
import { defineConfig } from "vite";
|
||||
import wasm from "vite-plugin-wasm";
|
||||
import { viteStaticCopy } from "vite-plugin-static-copy";
|
||||
import path from "path";
|
||||
import { fileURLToPath } from "url";
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
wasm(),
|
||||
viteStaticCopy({
|
||||
targets: [
|
||||
{
|
||||
src: path.resolve(__dirname, "../../../assets/icons"),
|
||||
dest: "assets",
|
||||
},
|
||||
],
|
||||
}),
|
||||
{
|
||||
name: "serve-assets",
|
||||
configureServer(server) {
|
||||
server.middlewares.use(
|
||||
"/coop/assets",
|
||||
(req, res, next) => {
|
||||
const assetsPath = path.resolve(__dirname, "../../../assets");
|
||||
const filePath = path.join(
|
||||
assetsPath,
|
||||
req.url.replace("/assets", ""),
|
||||
);
|
||||
|
||||
// Try to serve the file
|
||||
import("fs").then(({ default: fs }) => {
|
||||
if (fs.existsSync(filePath) && fs.statSync(filePath).isFile()) {
|
||||
res.setHeader("Access-Control-Allow-Origin", "*");
|
||||
if (filePath.endsWith(".svg")) {
|
||||
res.setHeader("Content-Type", "image/svg+xml");
|
||||
}
|
||||
fs.createReadStream(filePath).pipe(res);
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
});
|
||||
},
|
||||
);
|
||||
},
|
||||
},
|
||||
],
|
||||
build: {
|
||||
target: "esnext",
|
||||
minify: true,
|
||||
sourcemap: false,
|
||||
rollupOptions: {
|
||||
output: {
|
||||
manualChunks: undefined,
|
||||
},
|
||||
},
|
||||
},
|
||||
server: {
|
||||
port: 3000,
|
||||
open: true,
|
||||
fs: {
|
||||
strict: false,
|
||||
allow: [".."],
|
||||
},
|
||||
headers: {
|
||||
"Cross-Origin-Embedder-Policy": "require-corp",
|
||||
"Cross-Origin-Opener-Policy": "same-origin",
|
||||
},
|
||||
},
|
||||
optimizeDeps: {
|
||||
exclude: ["./src/wasm"],
|
||||
},
|
||||
base: "/",
|
||||
});
|
||||
Reference in New Issue
Block a user