omega restructuring + a bunch of changes i have made over the last weeks

This commit is contained in:
Sebastian Moser
2026-07-31 00:48:15 +02:00
parent c57849f748
commit b2ed9efff2
201 changed files with 4331 additions and 49073 deletions

View File

@@ -0,0 +1,269 @@
use dioxus::prelude::*;
use dioxus_web::events::FormEvent;
use mize::Mize;
use matrix_sdk::SyncRoomEvent;
const ROOM_ID: &str = "!XwqdXGPlmaLatdGUiN:ppc.social";
/// Props for the chat component
#[derive(Props, Clone)]
pub struct ChatProps {
pub mize: Mize,
pub initial_timeline: Vec<SyncRoomEvent>,
pub initial_draft: String,
pub initial_edit_id: Option<String>,
}
/// Message component - renders a single message
#[component]
pub fn Message(cx: Scope, event: SyncRoomEvent) -> Element {
let sender = event.sender().to_string();
let timestamp = event.origin_server_ts();
// Extract display name from MXID (basic version)
let display_name = if let Some(at_pos) = sender.find('@') {
if let Some(colon_pos) = sender.rfind(':') {
&sender[at_pos + 1..colon_pos]
} else {
&sender[at_pos + 1..]
}
} else {
&sender
};
// Format timestamp
let time_str = {
let dt = js_sys::Date::new(&(timestamp as f64));
dt.to_locale_string()
};
// Extract message content
let content = event
.as_original()
.and_then(|e| e.content().deserialize().ok())
.and_then(|c: matrix_sdk::ruma::events::room::message::RoomMessageEventContent| {
c.body().map(|s| s.to_string())
})
.unwrap_or_default();
// Check if this is an edit
let is_edit = event
.as_original()
.map(|e| {
e.content()
.get("m.relates_to")
.and_then(|v| v.as_object())
.and_then(|o| o.get("rel_type"))
.and_then(|v| v.as_str())
== Some("m.replace")
})
.unwrap_or(false);
cx.render(rsx! {
div {
class: "matrix-chat-event",
style: "margin: 14px 16px; padding-bottom: 10px; border-bottom: 1px solid var(--background-modifier-border);",
div {
class: "matrix-chat-msghead",
style: "font-size: 1em; font-weight: 500; color: var(--interactive-accent); display: flex; align-items: center; gap: 10px;",
span { display_name }
span {
style: "font-size: 0.85em; color: var(--text-muted); margin-left: auto;",
{time_str.clone()}
if is_edit { " · edited" }
}
}
div {
class: "matrix-chat-msgbody",
style: "margin: 6px 0 0 0; font-size: 1em;",
{content}
}
}
})
}
/// Editor component - message input area
#[component]
pub fn Editor(cx: Scope, mize: Mize, draft: UseSignal<String>, edit_id: UseSignal<Option<String>>) -> Element {
let on_input = move |evt: FormEvent| {
draft.set(evt.value.clone());
};
let on_send = move |_| {
let mize_clone = mize.clone();
let draft_val = draft.read().clone();
let edit_id_val = edit_id.read().clone();
cx.spawn(async move {
if let Ok(mut matrix_part) = mize_clone.get_part_native::<crate::matrix::MatrixPart>("matrix") {
matrix_part.message_draft = draft_val;
matrix_part.edit_event_id = edit_id_val;
if let Err(e) = matrix_part.send_message().await {
console_log!("Failed to send message: {:?}", e);
}
// Clear local draft
draft.set(String::new());
edit_id.set(None);
}
});
};
let on_keydown = move |evt: dioxus_web::events::KeyboardEvent| {
if (evt.ctrl_key() || evt.meta_key()) && evt.key() == "Enter" {
on_send(evt);
}
};
let on_cancel = move |_| {
draft.set(String::new());
edit_id.set(None);
};
cx.render(rsx! {
div {
class: "matrix-chat-editor",
style: "border-top: 1px solid var(--background-modifier-border); background: var(--background-primary); padding: 8px 12px;",
div {
class: "matrix-chat-editor-inner",
style: "border: 1px solid var(--background-modifier-border); border-radius: 6px; overflow: hidden; background: var(--background-secondary);",
textarea {
r#type: "text",
rows: "3",
style: "width: 99%; min-height: 40px; resize: vertical; background: transparent; border: none; outline: none; padding: 8px; font-family: inherit; font-size: inherit; color: var(--text-normal);",
value: "{draft}",
oninput: on_input,
onkeydown: on_keydown,
}
}
button {
r#type: "button",
style: "margin-top: 3px; float: right; padding: 6px 14px; font-size: 0.97em; border-radius: 5px; border: none; background: var(--interactive-accent); color: white; cursor: pointer;",
onclick: on_send,
if edit_id.read().is_some() { "Save" } else { "Send" }
}
if edit_id.read().is_some() {
button {
r#type: "button",
style: "margin-right: 12px; padding: 6px 12px; font-size: 0.93em; border-radius: 5px; border: none; color: var(--text-normal); background: var(--background-secondary); cursor: pointer;",
onclick: on_cancel,
"Cancel"
}
}
}
})
}
/// Timeline component - list of messages
#[component]
pub fn Timeline(cx: Scope, mize: Mize, timeline: UseSignal<Vec<SyncRoomEvent>>) -> Element {
// Periodically refresh timeline from MatrixPart
cx.use_effect((), move |_| {
let mize_clone = mize.clone();
let timeline_clone = timeline.clone();
// Set up interval to poll for updates
let interval = js_sys::set_interval(
&Closure::<dyn FnMut()>::wrap(Box::new(move || {
if let Ok(matrix_part) = mize_clone.get_part_native::<crate::matrix::MatrixPart>("matrix") {
*timeline_clone.write() = matrix_part.timeline.clone();
}
})),
1000, // 1 second
);
// Cleanup on unmount
move || {
js_sys::clear_interval(interval);
}
});
cx.render(rsx! {
div {
class: "matrix-chat-scroll",
style: "flex-grow: 1; overflow-y: auto; padding: 8px 0; background: var(--background-secondary);",
// Room name header
div {
class: "matrix-chat-roomname",
style: "font-weight: 600; text-align: center; font-size: 1.1em; margin: 2px 0 12px 0; border-bottom: 1px solid var(--background-modifier-border); color: var(--text-accent); background: var(--background-primary);",
"Matrix Chat - {ROOM_ID}"
}
// Messages
for event in timeline.read().iter() {
rsx! { Message { event: event.clone() } }
}
}
})
}
/// Root chat component
#[component]
pub fn Chat(cx: Scope, props: ChatProps) -> Element {
let timeline = use_signal(&cx, || props.initial_timeline);
let draft = use_signal(&cx, || props.initial_draft);
let edit_id = use_signal(&cx, || props.initial_edit_id);
cx.render(rsx! {
div {
class: "matrix-chat-root",
style: "height: 100%; display: flex; flex-direction: column; background: var(--background-primary); color: var(--text-normal);",
// Title
div {
class: "matrix-chat-title",
style: "padding: 12px; font-weight: bold; font-size: 1.2em; text-align: center; border-bottom: 1px solid var(--background-modifier-border);",
"Matrix Chat"
}
// Info
div {
class: "matrix-chat-info",
style: "font-size: 0.85em; color: var(--text-muted); text-align: center; margin-bottom: 5px;",
"Room: {ROOM_ID}"
}
// Timeline
Timeline { mize: props.mize.clone(), timeline }
// Editor
Editor { mize: props.mize.clone(), draft, edit_id }
}
})
}
/// Mount the Dioxus app into a DOM element
pub fn mount_chat_app(
element: web_sys::HtmlElement,
initial_timeline: Vec<SyncRoomEvent>,
initial_draft: String,
initial_edit_id: Option<String>,
mize: Mize,
) {
dioxus_web::launch(
dioxus::prelude::App::new(move || rsx! {
Chat {
mize: mize.clone(),
initial_timeline: initial_timeline.clone(),
initial_draft: initial_draft.clone(),
initial_edit_id: initial_edit_id.clone(),
}
}),
element,
);
}
// Console log macro
#[macro_export]
macro_rules! console_log {
($($t:tt)*) => {
web_sys::console::log_1(&format!($($t)*).into());
};
}