feat: Matcha! social integration — friends, chat, DMs, avatars, presence

Add full Matcha social panel (butter.lat API) as a right-side slide-out:

Backend (matchaService.js):
- HTTP client for auth, friends, messages, unread, avatar, heartbeat APIs
- WebSocket with auto-reconnect (exponential backoff, no hard cap)
- Token management via config, presence heartbeat every 30s
- WS error message type handling, game running presence

Renderer (matcha.js):
- State machine UI: intro → login/register → app (friends/chat/DMs/profile)
- Two-phase registration with master key display and verification
- Friends list with presence dots, collapsible requests, 12s polling
- Global chat + DM with optimistic rendering, cursor pagination
- Scroll position preserved on load-more, separate loading flags
- Clickable URLs in messages (linkify with proper escaping)
- User profile popup with avatar upload/delete
- Unread badges (messages + friend requests) on nav icon
- Escape key closes panel/overlay, try/catch on auth flows

IPC bridge (preload.js + main.js):
- 21 IPC invoke methods + 8 WS event listeners
- Avatar upload via file picker dialog in main process
- Game launch sets in_game heartbeat state

CSS (style.css):
- ~1500 lines: panel, auth screens, friends, chat, profile, toast
- Responsive panel width, improved contrast, no overflow clipping
- Loading states, disabled states, pulse animations

Credits: Powered by Butter Launcher & Matcha! (butterlauncher.tech)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
sanasol
2026-03-02 00:49:37 +01:00
parent 57056e5b7a
commit a40465cac9
9 changed files with 4219 additions and 5 deletions

View File

@@ -24,7 +24,7 @@
height="100%25" filter="url(%23noiseFilter)" opacity="0.1" /%3E%3C/svg%3E')] opacity-20"></div>
</div>
<div class="flex w-full h-screen relative z-10">
<div class="flex w-full h-screen relative z-10" style="isolation: isolate">
<nav class="sidebar">
<div class="sidebar-logo">
<img src="./icon.png" alt="Hytale Logo" />
@@ -52,9 +52,12 @@
<i class="fas fa-terminal"></i>
<span class="nav-tooltip">Logs</span>
</div>
<div class="nav-item" onclick="openDiscordExternal()">
<i class="fas fa-comments"></i>
<span class="nav-tooltip">Community Chat</span>
<div class="nav-item" id="matchaNavItem">
<i class="fas fa-comments" id="matchaNavIcon"></i>
<img id="matchaNavAvatar" class="matcha-nav-avatar" style="display:none" />
<span class="matcha-nav-status" id="matchaNavStatus" style="display:none"></span>
<span class="nav-tooltip">Matcha!</span>
<span id="matchaUnreadBadge" class="matcha-unread-badge" style="display:none"></span>
</div>
</div>
@@ -687,6 +690,29 @@
</main>
</div>
<!-- Matcha! Panel -->
<div id="matchaPanelBackdrop" class="matcha-panel-backdrop"></div>
<div id="matchaPanel" class="matcha-panel">
<div class="matcha-panel-header">
<div id="matchaPanelHeaderContent" class="matcha-panel-header-content">
<span class="matcha-header-title">Matcha!</span>
</div>
<button class="matcha-panel-close" id="matchaPanelCloseBtn">
<i class="fas fa-times"></i>
</button>
</div>
<div id="matchaPanelBody" class="matcha-panel-body"></div>
</div>
<!-- Matcha User Profile Popup -->
<div id="matchaUserProfileOverlay" class="matcha-user-profile-overlay" style="display:none">
<div class="matcha-user-profile-card" id="matchaUserProfileCard">
<div class="matcha-user-profile-body" id="matchaUserProfileBody">
<div class="matcha-loading"><i class="fas fa-spinner fa-spin"></i></div>
</div>
</div>
</div>
<div id="myModsModal" class="mods-modal">
<div class="mods-modal-content">
<div class="mods-modal-header">
@@ -969,6 +995,12 @@
<a href="#" onclick="window.electronAPI?.openExternal('https://github.com/xSamiVS'); return false;"
class="text-blue-400 hover:text-blue-300 transition-colors">@xSamiVS</a>
</span>
<span class="mx-2">|</span>
<span>Social powered by <a href="#" onclick="window.electronAPI?.openExternal('https://github.com/vZylev/Butter-Launcher'); return false;"
class="text-purple-400 hover:text-purple-300 transition-colors">Butter Launcher</a> &amp;
<a href="#" onclick="window.electronAPI?.openExternal('https://butterlauncher.tech/'); return false;"
class="text-purple-400 hover:text-purple-300 transition-colors">Matcha!</a>
</span>
</div>
</footer>