Files
BetterDesk/web-nodejs/views/chat.ejs
T
UNITRONIX dd0889e3d6 Add SessionManager; update docs, i18n & CI
Introduce a SessionManager for relay-based remote sessions in the Tauri MGMT client: new SessionCommand API, start/stop/session input routing, clipboard/recording/quality controls, and notification read/dismiss state. Wire AppState with new mutexes and show main window on startup. CI: add SBOM generation (anchore) and Trivy vulnerability scan steps. Misc: change console Docker DB path, large README/CHANGELOG updates (chat E2E, unattended access/WOL, i18n expansion, CDAP/SDK docs), and many web-nodejs assets/locales/routes/views/services and server-side changes.
2026-04-05 13:42:07 +02:00

188 lines
9.6 KiB
HTML

<%- include('layouts/main', {
title: typeof title !== 'undefined' ? title : _('nav.chat'),
pageStyles: typeof pageStyles !== 'undefined' ? pageStyles : ['chat'],
pageScripts: typeof pageScripts !== 'undefined' ? pageScripts : ['chatCrypto', 'chat'],
currentPage: typeof currentPage !== 'undefined' ? currentPage : 'chat',
breadcrumb: typeof breadcrumb !== 'undefined' ? breadcrumb : [{ label: _('nav.chat') }],
body: `
<div class="chat-page" id="chat-page">
<!-- Sidebar: contacts & groups -->
<aside class="chat-sidebar" id="chat-sidebar">
<div class="chat-sidebar-header">
<h2 class="chat-sidebar-title">${_('nav.chat')}</h2>
<div class="chat-sidebar-actions">
<button class="chat-icon-btn" id="chat-new-group-btn" title="${_('chat.create_group')}">
<span class="material-icons">group_add</span>
</button>
<button class="chat-icon-btn" id="chat-search-toggle" title="${_('chat.search_messages')}">
<span class="material-icons">search</span>
</button>
</div>
</div>
<!-- Search bar (hidden by default) -->
<div class="chat-search-bar" id="chat-search-bar" style="display:none">
<input type="text" class="chat-search-input" id="chat-search-input"
placeholder="${_('chat.search_placeholder')}">
<button class="chat-icon-btn chat-search-close" id="chat-search-close">
<span class="material-icons">close</span>
</button>
</div>
<div class="chat-search-results" id="chat-search-results" style="display:none"></div>
<!-- Tabs: Contacts / Groups -->
<div class="chat-tabs">
<button class="chat-tab active" data-tab="contacts">
<span class="material-icons">people</span>
${_('chat.contacts')}
</button>
<button class="chat-tab" data-tab="groups">
<span class="material-icons">groups</span>
${_('chat.groups')}
</button>
</div>
<div class="chat-list-wrap">
<!-- Contact list -->
<div class="chat-list" id="chat-contacts-list" data-tab-content="contacts">
<div class="chat-list-empty">
<span class="material-icons">forum</span>
<p>${_('chat.no_contacts')}</p>
</div>
</div>
<!-- Group list -->
<div class="chat-list" id="chat-groups-list" data-tab-content="groups" style="display:none">
<div class="chat-list-empty">
<span class="material-icons">group</span>
<p>${_('chat.no_groups')}</p>
</div>
</div>
</div>
<!-- Presence selector -->
<div class="chat-presence-bar" id="chat-presence-bar">
<select class="chat-presence-select" id="chat-presence-select">
<option value="online">${_('chat.presence_online')}</option>
<option value="away">${_('chat.presence_away')}</option>
<option value="busy">${_('chat.presence_busy')}</option>
</select>
<span class="chat-presence-dot" id="chat-my-presence-dot"></span>
<span class="chat-username">${typeof user !== 'undefined' && user ? user.username : 'Operator'}</span>
</div>
</aside>
<!-- Main chat area -->
<section class="chat-main" id="chat-main">
<!-- Empty state -->
<div class="chat-empty-state" id="chat-empty-state">
<span class="material-icons chat-empty-icon">chat</span>
<h3>${_('chat.select_conversation')}</h3>
<p>${_('chat.select_conversation_hint')}</p>
</div>
<!-- Conversation view (hidden initially) -->
<div class="chat-conversation" id="chat-conversation" style="display:none">
<!-- Conversation header -->
<div class="chat-conv-header" id="chat-conv-header">
<button class="chat-icon-btn chat-back-btn" id="chat-back-btn" title="${_('actions.back')}">
<span class="material-icons">arrow_back</span>
</button>
<div class="chat-conv-info">
<div class="chat-conv-avatar" id="chat-conv-avatar"></div>
<div class="chat-conv-details">
<span class="chat-conv-name" id="chat-conv-name"></span>
<span class="chat-conv-status" id="chat-conv-status"></span>
</div>
</div>
<div class="chat-conv-actions">
<button class="chat-icon-btn" id="chat-encrypt-btn" title="${_('chat.e2e_enabled')}">
<span class="material-icons">lock</span>
</button>
<button class="chat-icon-btn" id="chat-conv-search-btn" title="${_('chat.search_messages')}">
<span class="material-icons">search</span>
</button>
<button class="chat-icon-btn" id="chat-conv-info-btn" title="${_('chat.info')}">
<span class="material-icons">info</span>
</button>
</div>
</div>
<!-- E2E encryption banner -->
<div class="chat-e2e-banner" id="chat-e2e-banner" style="display:none">
<span class="material-icons">enhanced_encryption</span>
<span id="chat-e2e-text">${_('chat.e2e_establishing')}</span>
</div>
<!-- Messages area -->
<div class="chat-messages" id="chat-messages">
<div class="chat-messages-inner" id="chat-messages-inner"></div>
</div>
<!-- Typing indicator -->
<div class="chat-typing" id="chat-typing" style="display:none">
<span class="chat-typing-dots">
<span></span><span></span><span></span>
</span>
<span class="chat-typing-text" id="chat-typing-text">${_('chat.typing_indicator')}</span>
</div>
<!-- Input area -->
<div class="chat-input-area" id="chat-input-area">
<div class="chat-input-row">
<button class="chat-icon-btn" id="chat-attach-btn" title="${_('chat.attach_file')}">
<span class="material-icons">attach_file</span>
</button>
<button class="chat-icon-btn" id="chat-emoji-btn" title="${_('chat.emoji')}">
<span class="material-icons">sentiment_satisfied_alt</span>
</button>
<div class="chat-input-wrap">
<textarea class="chat-input" id="chat-input" rows="1"
placeholder="${_('chat.type_message')}" maxlength="4096"></textarea>
</div>
<button class="chat-send-btn" id="chat-send-btn" title="${_('chat.send')}">
<span class="material-icons">send</span>
</button>
</div>
<!-- File preview (hidden) -->
<div class="chat-file-preview" id="chat-file-preview" style="display:none">
<span class="chat-file-name" id="chat-file-name"></span>
<span class="chat-file-size" id="chat-file-size"></span>
<button class="chat-icon-btn chat-file-remove" id="chat-file-remove">
<span class="material-icons">close</span>
</button>
</div>
<input type="file" id="chat-file-input" style="display:none">
</div>
</div>
</section>
</div>
<!-- Create Group Modal -->
<div class="modal-overlay" id="chat-group-modal" style="display:none">
<div class="modal-dialog">
<div class="modal-header">
<h3>${_('chat.create_group')}</h3>
<button class="modal-close" id="chat-group-modal-close">&times;</button>
</div>
<div class="modal-body">
<div class="form-group">
<label>${_('chat.group_name')}</label>
<input type="text" class="form-input" id="chat-group-name-input"
placeholder="${_('chat.group_name_placeholder')}" maxlength="64">
</div>
<div class="form-group">
<label>${_('chat.group_members')}</label>
<div class="chat-member-select" id="chat-member-select"></div>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-secondary" id="chat-group-cancel">${_('actions.cancel')}</button>
<button class="btn btn-primary" id="chat-group-create">${_('actions.create')}</button>
</div>
</div>
</div>
<!-- Emoji Picker (lightweight) -->
<div class="chat-emoji-picker" id="chat-emoji-picker" style="display:none"></div>
` }) %>