diff --git a/warzone/Cargo.lock b/warzone/Cargo.lock index 2e4edba..b2495bc 100644 --- a/warzone/Cargo.lock +++ b/warzone/Cargo.lock @@ -2956,7 +2956,7 @@ dependencies = [ [[package]] name = "warzone-client" -version = "0.0.29" +version = "0.0.30" dependencies = [ "anyhow", "argon2", @@ -2989,7 +2989,7 @@ dependencies = [ [[package]] name = "warzone-mule" -version = "0.0.29" +version = "0.0.30" dependencies = [ "anyhow", "clap", @@ -2998,7 +2998,7 @@ dependencies = [ [[package]] name = "warzone-protocol" -version = "0.0.29" +version = "0.0.30" dependencies = [ "base64", "bincode", @@ -3023,7 +3023,7 @@ dependencies = [ [[package]] name = "warzone-server" -version = "0.0.29" +version = "0.0.30" dependencies = [ "anyhow", "axum", @@ -3053,7 +3053,7 @@ dependencies = [ [[package]] name = "warzone-wasm" -version = "0.0.29" +version = "0.0.30" dependencies = [ "base64", "bincode", diff --git a/warzone/Cargo.toml b/warzone/Cargo.toml index 8c962bf..2b922d9 100644 --- a/warzone/Cargo.toml +++ b/warzone/Cargo.toml @@ -9,7 +9,7 @@ members = [ ] [workspace.package] -version = "0.0.29" +version = "0.0.30" edition = "2021" license = "MIT" rust-version = "1.75" diff --git a/warzone/crates/warzone-protocol/Cargo.toml b/warzone/crates/warzone-protocol/Cargo.toml index fdea9bb..a22607d 100644 --- a/warzone/crates/warzone-protocol/Cargo.toml +++ b/warzone/crates/warzone-protocol/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "warzone-protocol" -version = "0.0.29" +version = "0.0.30" edition = "2021" license = "MIT" description = "Core crypto & wire protocol for featherChat (Warzone messenger)" diff --git a/warzone/crates/warzone-server/src/routes/web.rs b/warzone/crates/warzone-server/src/routes/web.rs index 35695a2..b8dd28f 100644 --- a/warzone/crates/warzone-server/src/routes/web.rs +++ b/warzone/crates/warzone-server/src/routes/web.rs @@ -50,7 +50,7 @@ async fn pwa_manifest() -> impl IntoResponse { async fn service_worker() -> impl IntoResponse { ([(header::CONTENT_TYPE, "application/javascript")], r##" -const CACHE = 'wz-v11'; +const CACHE = 'wz-v12'; const SHELL = ['/', '/wasm/warzone_wasm.js', '/wasm/warzone_wasm_bg.wasm', '/icon.svg', '/manifest.json']; self.addEventListener('install', e => { @@ -154,8 +154,18 @@ const WEB_HTML: &str = r##" #chat-header input { background: #1a1a2e; border: 1px solid #333; color: #e6a23c; padding: 2px 6px; border-radius: 3px; font-family: inherit; font-size: 0.85em; width: 280px; } - #messages { flex: 1; overflow-y: auto; padding: 8px 10px; -webkit-overflow-scrolling: touch; } + #messages { flex: 1; overflow-y: scroll; padding: 8px 10px; -webkit-overflow-scrolling: touch; min-height: 0; } .msg { padding: 2px 0; font-size: 0.85em; white-space: pre-wrap; word-wrap: break-word; } + .msg code { background: #1a1a3e; padding: 1px 4px; border-radius: 3px; font-size: 0.95em; color: #4fc3f7; } + .msg pre { background: #0d0d20; padding: 8px; border-radius: 4px; margin: 4px 0; overflow-x: auto; border: 1px solid #222; } + .msg pre code { background: none; padding: 0; } + .msg strong, .msg b { color: #fff; } + .msg em, .msg i { color: #e6a23c; } + .msg a { color: #4fc3f7; } + .msg blockquote { border-left: 3px solid #444; padding-left: 8px; color: #888; margin: 4px 0; } + .msg ul, .msg ol { padding-left: 20px; margin: 4px 0; } + .msg h1, .msg h2, .msg h3 { color: #fff; margin: 6px 0 2px; } + .msg h1 { font-size: 1.2em; } .msg h2 { font-size: 1.1em; } .msg h3 { font-size: 1em; } .msg .ts { color: #333; margin-right: 4px; } .msg .from-self { color: #4ade80; font-weight: bold; } .msg .from-sys { color: #5e9ca0; font-style: italic; } @@ -241,7 +251,7 @@ let pollTimer = null; let ws = null; // WebSocket connection let wasmReady = false; -const VERSION = '0.0.29'; +const VERSION = '0.0.30'; let DEBUG = true; // toggle with /debug command // ── Receipt tracking ── @@ -737,6 +747,34 @@ function esc(s) { return d.innerHTML; } +function renderMd(text) { + let s = esc(text); + // Code blocks: ```...``` + s = s.replace(/```(\w*)\n?([\s\S]*?)```/g, '
$2');
+ // Inline code: `...`
+ s = s.replace(/`([^`]+)`/g, '$1');
+ // Bold: **...**
+ s = s.replace(/\*\*(.+?)\*\*/g, '$1');
+ // Italic: *...*
+ s = s.replace(/(?$1');
+ // Headers: ### ... (at line start)
+ s = s.replace(/^### (.+)$/gm, '$1'); + // Unordered lists: - ... + s = s.replace(/^- (.+)$/gm, '
([\s\S]*?)<\/code><\/pre>/g, (m, code) => '' + code.replace(/
/g, '\n') + '
');
+ return s;
+}
+
const PEER_COLORS = ['#e6a23c','#f56c9d','#67c7eb','#b39ddb','#ff8a65','#81c784','#ce93d8','#4fc3f7','#ffb74d','#aed581','#f06292','#4dd0e1'];
function peerColor(name) {
@@ -813,7 +851,7 @@ function addMsg(from, text, isSelf, messageId, rawHtml) {
const status = (sentMsgReceipts[messageId] && sentMsgReceipts[messageId].status) || 'sent';
receiptHtml = ' ' + receiptIndicator(status) + '';
}
- const bodyHtml = rawHtml ? text : makeAddressClickable(esc(text));
+ const bodyHtml = rawHtml ? text : makeAddressClickable(renderMd(text));
d.innerHTML = '' + ts() + ' ' + lock + '' + makeAddressClickable(esc(from)) + ': ' + bodyHtml + receiptHtml;
// Attach click handler for .addr spans
d.querySelectorAll('.addr').forEach(el => {