mirror of
https://github.com/RedWizardsLab/EchoHub.git
synced 2026-09-05 07:36:03 +02:00
deploy: 4d25458717
This commit is contained in:
@@ -258,6 +258,48 @@ export Server__PublicServer=true
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h3 id="uploads">Uploads</h3>
|
||||
<p>Per-attachment size limits by kind (in megabytes) and the per-message attachment cap. An
|
||||
absent or partial <code>Uploads</code> section keeps the built-in defaults. See
|
||||
<a href="messages-and-attachments.html">Messages & Attachments</a> for how kinds are detected.</p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Key</th>
|
||||
<th>Default</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>Uploads:MaxImageSizeMB</code></td>
|
||||
<td><code>10</code></td>
|
||||
<td>Max size for one image attachment</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>Uploads:MaxAudioSizeMB</code></td>
|
||||
<td><code>10</code></td>
|
||||
<td>Max size for one audio attachment</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>Uploads:MaxFileSizeMB</code></td>
|
||||
<td><code>100</code></td>
|
||||
<td>Max size for any other attachment</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>Uploads:MaxAvatarSizeMB</code></td>
|
||||
<td><code>2</code></td>
|
||||
<td>Max avatar upload size</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>Uploads:MaxAttachmentsPerMessage</code></td>
|
||||
<td><code>10</code></td>
|
||||
<td>Attachments allowed on a single message</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>The server sizes its request-body limits from these values, so raising a limit here is all
|
||||
that's needed — no separate Kestrel tuning.</p>
|
||||
<h3 id="encryption">Encryption</h3>
|
||||
<table>
|
||||
<thead>
|
||||
|
||||
@@ -95,7 +95,7 @@
|
||||
<pre><code class="lang-bash">curl -sSfL https://raw.githubusercontent.com/HueByte/EchoHub/master/scripts/install.sh | sh
|
||||
</code></pre>
|
||||
<p>To install a specific version or to a custom directory:</p>
|
||||
<pre><code class="lang-bash">curl -sSfL .../install.sh | sh -s -- --version 0.2.11
|
||||
<pre><code class="lang-bash">curl -sSfL .../install.sh | sh -s -- --version 0.2.14
|
||||
curl -sSfL .../install.sh | sh -s -- --install-dir /opt/echohub
|
||||
</code></pre>
|
||||
<h3 id="manual-download">Manual Download</h3>
|
||||
@@ -132,9 +132,9 @@ Connect to a server, register an account, and start chatting.</p>
|
||||
<p>Then connect with any standard IRC client:</p>
|
||||
<pre><code class="lang-bash">irssi -c localhost -p 6667 -w <password> -n <username>
|
||||
</code></pre>
|
||||
<p>IRC users must have an existing EchoHub account. Authentication works via <code>PASS</code>/<code>NICK</code>/<code>USER</code> or SASL PLAIN. Messages flow bidirectionally between IRC and TUI clients.</p>
|
||||
<p>Your nick is your EchoHub username and the server password is your account password (<code>PASS</code>/<code>NICK</code>/<code>USER</code> or SASL PLAIN). Connecting with a new username registers the account. Messages flow bidirectionally between IRC and TUI clients.</p>
|
||||
<p>For TLS, set <code>TlsEnabled: true</code>, <code>TlsPort: 6697</code>, and provide a PKCS#12 certificate path.</p>
|
||||
<p>See the <a href="architecture.html">Architecture</a> page for details on how the IRC gateway integrates with the chat service.</p>
|
||||
<p>See the <a href="irc-gateway.html">IRC Gateway guide</a> for command mapping, attachment rendering, and limitations, or <a href="architecture.html">Architecture</a> for how the gateway integrates with the chat service.</p>
|
||||
<h2 id="configuration">Configuration</h2>
|
||||
<p>Server configuration is in <code>appsettings.json</code> (auto-generated on first run). You can also use environment variables or command-line arguments to override settings.</p>
|
||||
<p>See the <a href="configuration.html">Configuration</a> guide for the full reference and how it all works.</p>
|
||||
|
||||
@@ -0,0 +1,236 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>IRC Gateway | EchoHub Documentation </title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="title" content="IRC Gateway | EchoHub Documentation ">
|
||||
|
||||
|
||||
<link rel="icon" href="../images/hue_icon.svg">
|
||||
<link rel="stylesheet" href="../public/docfx.min.css">
|
||||
<link rel="stylesheet" href="../public/main.css">
|
||||
<meta name="docfx:navrel" content="../toc.html">
|
||||
<meta name="docfx:tocrel" content="toc.html">
|
||||
|
||||
<meta name="docfx:rel" content="../">
|
||||
|
||||
|
||||
<meta name="docfx:docurl" content="https://github.com/HueByte/EchoHub/blob/master/docs/#L1">
|
||||
<meta name="loc:inThisArticle" content="In this article">
|
||||
<meta name="loc:searchResultsCount" content="{count} results for "{query}"">
|
||||
<meta name="loc:searchNoResults" content="No results for "{query}"">
|
||||
<meta name="loc:tocFilter" content="Filter by title">
|
||||
<meta name="loc:nextArticle" content="Next">
|
||||
<meta name="loc:prevArticle" content="Previous">
|
||||
<meta name="loc:themeLight" content="Light">
|
||||
<meta name="loc:themeDark" content="Dark">
|
||||
<meta name="loc:themeAuto" content="Auto">
|
||||
<meta name="loc:changeTheme" content="Change theme">
|
||||
<meta name="loc:copy" content="Copy">
|
||||
<meta name="loc:downloadPdf" content="Download PDF">
|
||||
|
||||
<script type="module" src="./../public/docfx.min.js"></script>
|
||||
|
||||
<script>
|
||||
const theme = localStorage.getItem('theme') || 'auto'
|
||||
document.documentElement.setAttribute('data-bs-theme', theme === 'auto' ? (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light') : theme)
|
||||
</script>
|
||||
|
||||
</head>
|
||||
|
||||
<body class="tex2jax_ignore" data-layout="" data-yaml-mime="">
|
||||
<header class="bg-body border-bottom">
|
||||
<nav id="autocollapse" class="navbar navbar-expand-md" role="navigation">
|
||||
<div class="container-xxl flex-nowrap">
|
||||
<a class="navbar-brand" href="../index.html">
|
||||
<img id="logo" class="svg" src="../images/hue_icon.svg" alt="EchoHub">
|
||||
EchoHub
|
||||
</a>
|
||||
<button class="btn btn-lg d-md-none border-0" type="button" data-bs-toggle="collapse" data-bs-target="#navpanel" aria-controls="navpanel" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<i class="bi bi-three-dots"></i>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navpanel">
|
||||
<div id="navbar">
|
||||
<form class="search" role="search" id="search">
|
||||
<i class="bi bi-search"></i>
|
||||
<input class="form-control" id="search-query" type="search" disabled placeholder="Search" autocomplete="off" aria-label="Search">
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<main class="container-xxl">
|
||||
<div class="toc-offcanvas">
|
||||
<div class="offcanvas-md offcanvas-start" tabindex="-1" id="tocOffcanvas" aria-labelledby="tocOffcanvasLabel">
|
||||
<div class="offcanvas-header">
|
||||
<h5 class="offcanvas-title" id="tocOffcanvasLabel">Table of Contents</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="offcanvas" data-bs-target="#tocOffcanvas" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="offcanvas-body">
|
||||
<nav class="toc" id="toc"></nav>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<div class="actionbar">
|
||||
<button class="btn btn-lg border-0 d-md-none" type="button" data-bs-toggle="offcanvas" data-bs-target="#tocOffcanvas" aria-controls="tocOffcanvas" aria-expanded="false" aria-label="Show table of contents">
|
||||
<i class="bi bi-list"></i>
|
||||
</button>
|
||||
|
||||
<nav id="breadcrumb"></nav>
|
||||
</div>
|
||||
|
||||
<article data-uid="">
|
||||
<h1 id="irc-gateway">IRC Gateway</h1>
|
||||
|
||||
<p>Every EchoHub server can expose a second door: a built-in <strong>IRC gateway</strong> that speaks the
|
||||
classic IRC protocol on port 6667. Any standard IRC client — irssi, WeeChat, HexChat,
|
||||
Halloy — can join the same channels as TUI users, see the same messages, and chat with the
|
||||
same accounts. Under the hood both protocols call the same chat service, so a message sent
|
||||
from IRC appears instantly in the TUI and vice versa (see <a href="architecture.html">Architecture</a>).</p>
|
||||
<h2 id="enabling-the-gateway">Enabling the gateway</h2>
|
||||
<p>The gateway is off by default. Enable it in <code>appsettings.json</code> (or <code>Irc__Enabled=true</code> as an
|
||||
environment variable):</p>
|
||||
<pre><code class="lang-json">{
|
||||
"Irc": {
|
||||
"Enabled": true,
|
||||
"Port": 6667,
|
||||
"TlsEnabled": false,
|
||||
"TlsPort": 6697,
|
||||
"TlsCertPath": "",
|
||||
"ServerName": "echohub",
|
||||
"Motd": "Welcome to EchoHub IRC Gateway!"
|
||||
}
|
||||
}
|
||||
</code></pre>
|
||||
<p>The plaintext listener always starts on <code>Port</code>. The TLS listener on <code>TlsPort</code> starts only
|
||||
when <code>TlsEnabled</code> is <code>true</code> <strong>and</strong> <code>TlsCertPath</code> points to a PKCS#12 (<code>.pfx</code>) certificate.
|
||||
See the <a href="configuration.html#irc-gateway">configuration reference</a> for every option.</p>
|
||||
<h2 id="connecting--authentication">Connecting & authentication</h2>
|
||||
<p>Your IRC <strong>nick is your EchoHub username</strong> and your server password is your <strong>account
|
||||
password</strong>. Two flows are supported:</p>
|
||||
<pre><code class="lang-bash"># classic PASS/NICK/USER — most clients call this the "server password"
|
||||
irssi -c chat.example.com -p 6667 -w <password> -n <username>
|
||||
</code></pre>
|
||||
<p>or <strong>SASL PLAIN</strong> (advertised via <code>CAP LS</code>), where the SASL username/password are the account
|
||||
credentials.</p>
|
||||
<p>A few things worth knowing:</p>
|
||||
<ul>
|
||||
<li><strong>Connecting auto-registers.</strong> If the username doesn't exist yet, the gateway creates the
|
||||
account with that password (usernames: 3–50 chars of <code>a-z 0-9 _ -</code>; passwords: 6+ chars).
|
||||
The very first account ever created on a server becomes the <strong>Owner</strong>.</li>
|
||||
<li>Because of that, a typo'd password for an <em>existing</em> account fails with
|
||||
<code>Username is already taken</code> — the gateway tried to log in, couldn't, then tried to register
|
||||
the name. If you see that error, re-check your password.</li>
|
||||
<li>Connecting without a password is rejected: <code>Password required. Use PASS command or SASL PLAIN.</code></li>
|
||||
</ul>
|
||||
<h2 id="what-maps-to-what">What maps to what</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>IRC</th>
|
||||
<th>EchoHub</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>JOIN #room</code></td>
|
||||
<td>Join a channel (history is replayed on join)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>JOIN #room <key></code></td>
|
||||
<td>Join a password-protected (<code>+k</code>) channel</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>PART</code> / <code>QUIT</code></td>
|
||||
<td>Leave channel / disconnect</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>LIST</code></td>
|
||||
<td>Public channels only (password-protected ones show a <code>[+k]</code> hint)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>TOPIC</code></td>
|
||||
<td>Read or set the channel topic (permission-checked)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>NAMES</code> / <code>WHO</code></td>
|
||||
<td>Online users in the channel</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>WHOIS</code></td>
|
||||
<td>Profile: display name, channels, idle time, away status</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>AWAY [message]</code></td>
|
||||
<td>Sets your EchoHub status to Away / back to Online</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>MODE #room +k <key></code> / <code>-k</code></td>
|
||||
<td>Set / clear the channel password</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>Private (unlisted) channels don't appear in <code>LIST</code>, but members who know the exact name can
|
||||
still <code>JOIN</code> them. Channels are not auto-created from IRC — create them from the TUI first.</p>
|
||||
<h2 id="how-messages-look">How messages look</h2>
|
||||
<ul>
|
||||
<li><strong>Attachments</strong> arrive as labeled link lines — <code>[Image: photo.png] https://…</code>,
|
||||
<code>♪ [Audio: song.mp3] https://…</code>, <code>[File: report.pdf] https://…</code> — and image attachments
|
||||
additionally render their <strong>ASCII-art preview</strong> using truecolor ANSI escapes, so a modern
|
||||
terminal IRC client shows actual picture previews.</li>
|
||||
<li><strong>Link embeds</strong> are appended as <code>│</code>-prefixed text lines.</li>
|
||||
<li>Long messages are split at word boundaries into IRC-safe lines (~400 bytes each);
|
||||
incoming messages may be up to 2,000 characters like any EchoHub message.</li>
|
||||
<li>Your own messages aren't echoed back (standard IRC convention).</li>
|
||||
<li>Moderation actions surface natively: kicks arrive as <code>KICK</code>, bans and channel nukes as
|
||||
server <code>NOTICE</code>s.</li>
|
||||
</ul>
|
||||
<h2 id="limitations">Limitations</h2>
|
||||
<p>The gateway bridges what IRC can express — and deliberately refuses what it can't:</p>
|
||||
<ul>
|
||||
<li><strong>No end-to-end encrypted rooms.</strong> Joining an <a href="encrypted-rooms.html">encrypted room</a> fails
|
||||
with <em>"Cannot join channel — end-to-end encrypted, use the EchoHub client."</em> Bridging one
|
||||
would require the server to hold the room key, breaking the zero-knowledge design.</li>
|
||||
<li><strong>No private messages.</strong> <code>PRIVMSG</code> to a nick is rejected; EchoHub is channel-based.</li>
|
||||
<li><strong>Usernames, not display names.</strong> Messages are attributed to the account username;
|
||||
a user's display name is visible via <code>WHOIS</code>/<code>WHO</code> (realname field).</li>
|
||||
<li><strong>No client features.</strong> Uploading attachments, profiles, themes, and reactions to status
|
||||
changes are TUI-client features. Other users' status changes aren't pushed to IRC —
|
||||
discover them with <code>WHOIS</code>/<code>WHO</code>.</li>
|
||||
</ul>
|
||||
<h2 id="how-irc-users-appear-to-tui-users">How IRC users appear to TUI users</h2>
|
||||
<p>Users connected <em>only</em> through the gateway are tagged <code>[irc]</code> in the users panel — a hint
|
||||
that they can't receive encrypted content or use client-side features. Someone connected
|
||||
with both an IRC client and the TUI shows untagged.</p>
|
||||
|
||||
</article>
|
||||
|
||||
<div class="contribution d-print-none">
|
||||
<a href="https://github.com/HueByte/EchoHub/blob/master/docs/#L1" class="edit-link">Edit this page</a>
|
||||
</div>
|
||||
|
||||
<div class="next-article d-print-none border-top" id="nextArticle"></div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="affix">
|
||||
<nav id="affix"></nav>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<div class="container-xxl search-results" id="search-results"></div>
|
||||
|
||||
<footer class="border-top text-secondary">
|
||||
<div class="container-xxl">
|
||||
<div class="flex-fill">
|
||||
<div class='footer-custom'><div class='footer-inner'><span class='footer-brand'>EchoHub</span><span class='footer-sep'>·</span><a href='https://github.com/HueByte/EchoHub'>GitHub</a><span class='footer-sep'>·</span><a href='https://echohub.voidcube.cloud'>Website</a></div></div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,264 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Messages & Attachments | EchoHub Documentation </title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="title" content="Messages & Attachments | EchoHub Documentation ">
|
||||
|
||||
|
||||
<link rel="icon" href="../images/hue_icon.svg">
|
||||
<link rel="stylesheet" href="../public/docfx.min.css">
|
||||
<link rel="stylesheet" href="../public/main.css">
|
||||
<meta name="docfx:navrel" content="../toc.html">
|
||||
<meta name="docfx:tocrel" content="toc.html">
|
||||
|
||||
<meta name="docfx:rel" content="../">
|
||||
|
||||
|
||||
<meta name="docfx:docurl" content="https://github.com/HueByte/EchoHub/blob/master/docs/#L1">
|
||||
<meta name="loc:inThisArticle" content="In this article">
|
||||
<meta name="loc:searchResultsCount" content="{count} results for "{query}"">
|
||||
<meta name="loc:searchNoResults" content="No results for "{query}"">
|
||||
<meta name="loc:tocFilter" content="Filter by title">
|
||||
<meta name="loc:nextArticle" content="Next">
|
||||
<meta name="loc:prevArticle" content="Previous">
|
||||
<meta name="loc:themeLight" content="Light">
|
||||
<meta name="loc:themeDark" content="Dark">
|
||||
<meta name="loc:themeAuto" content="Auto">
|
||||
<meta name="loc:changeTheme" content="Change theme">
|
||||
<meta name="loc:copy" content="Copy">
|
||||
<meta name="loc:downloadPdf" content="Download PDF">
|
||||
|
||||
<script type="module" src="./../public/docfx.min.js"></script>
|
||||
|
||||
<script>
|
||||
const theme = localStorage.getItem('theme') || 'auto'
|
||||
document.documentElement.setAttribute('data-bs-theme', theme === 'auto' ? (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light') : theme)
|
||||
</script>
|
||||
|
||||
</head>
|
||||
|
||||
<body class="tex2jax_ignore" data-layout="" data-yaml-mime="">
|
||||
<header class="bg-body border-bottom">
|
||||
<nav id="autocollapse" class="navbar navbar-expand-md" role="navigation">
|
||||
<div class="container-xxl flex-nowrap">
|
||||
<a class="navbar-brand" href="../index.html">
|
||||
<img id="logo" class="svg" src="../images/hue_icon.svg" alt="EchoHub">
|
||||
EchoHub
|
||||
</a>
|
||||
<button class="btn btn-lg d-md-none border-0" type="button" data-bs-toggle="collapse" data-bs-target="#navpanel" aria-controls="navpanel" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<i class="bi bi-three-dots"></i>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navpanel">
|
||||
<div id="navbar">
|
||||
<form class="search" role="search" id="search">
|
||||
<i class="bi bi-search"></i>
|
||||
<input class="form-control" id="search-query" type="search" disabled placeholder="Search" autocomplete="off" aria-label="Search">
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<main class="container-xxl">
|
||||
<div class="toc-offcanvas">
|
||||
<div class="offcanvas-md offcanvas-start" tabindex="-1" id="tocOffcanvas" aria-labelledby="tocOffcanvasLabel">
|
||||
<div class="offcanvas-header">
|
||||
<h5 class="offcanvas-title" id="tocOffcanvasLabel">Table of Contents</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="offcanvas" data-bs-target="#tocOffcanvas" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="offcanvas-body">
|
||||
<nav class="toc" id="toc"></nav>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<div class="actionbar">
|
||||
<button class="btn btn-lg border-0 d-md-none" type="button" data-bs-toggle="offcanvas" data-bs-target="#tocOffcanvas" aria-controls="tocOffcanvas" aria-expanded="false" aria-label="Show table of contents">
|
||||
<i class="bi bi-list"></i>
|
||||
</button>
|
||||
|
||||
<nav id="breadcrumb"></nav>
|
||||
</div>
|
||||
|
||||
<article data-uid="">
|
||||
<h1 id="messages--attachments">Messages & Attachments</h1>
|
||||
|
||||
<p>An EchoHub message is <strong>text content plus up to 10 attachments</strong>, Discord-style. A plain chat
|
||||
line is just a message with no attachments; a photo dump is one message with several files and
|
||||
an optional caption. This page explains how to attach files, what happens to them on the way to
|
||||
the server, and how other clients receive them.</p>
|
||||
<h2 id="message-basics">Message basics</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Limit</th>
|
||||
<th>Value</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Max message length</td>
|
||||
<td>2,000 characters</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Max newlines per message</td>
|
||||
<td>30 (no blank-line runs)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Max attachments per message</td>
|
||||
<td>10</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Link embeds per message</td>
|
||||
<td>first 3 URLs</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>Multiline messages are written with <code>Ctrl+N</code> for a newline; <code>Enter</code> sends. URLs in a message
|
||||
get link embeds (title, description, theme color) fetched by the server.</p>
|
||||
<h2 id="attaching-files">Attaching files</h2>
|
||||
<p>All of these end up in the same place — the <strong>staging tray</strong> — and are sent together as one
|
||||
message the next time you press <code>Enter</code>, with whatever you've typed as the caption:</p>
|
||||
<ul>
|
||||
<li><strong>Paste a copied file</strong> — copy one <em>or several</em> files in your file manager and press
|
||||
<code>Ctrl+V</code> in the input. All of them are staged at once.</li>
|
||||
<li><strong>Paste an image from the clipboard</strong> — copy an image in a browser (right-click → <em>Copy
|
||||
image</em>), take a screenshot (<code>Win+Shift+S</code>), or copy from an image editor, then <code>Ctrl+V</code>.
|
||||
The image is attached directly as a PNG named <code>image.png</code> — no saving to disk first.
|
||||
On Linux this uses <code>wl-paste</code> or <code>xclip</code>; on macOS it requires
|
||||
<a href="https://github.com/jcsalterego/pngpaste"><code>pngpaste</code></a> (<code>brew install pngpaste</code>).</li>
|
||||
<li><strong>Drag & drop</strong> — drop a file onto the terminal window; the client recognizes the dropped
|
||||
path and stages the file.</li>
|
||||
<li><strong><code>/send <filepath></code></strong> — stage a file by path (quote paths containing spaces).</li>
|
||||
</ul>
|
||||
<p>The input frame's title shows what's currently staged. <code>/clear</code> drops all staged attachments
|
||||
without sending. Sending with an empty input is fine — the message is just the attachments.</p>
|
||||
<pre><code class="lang-text">┌ Message (2 attached: report.pdf, image.png) ──────────────┐
|
||||
│ here's the summary and a screenshot_ │
|
||||
└────────────────────────────────────────────────────────────┘
|
||||
</code></pre>
|
||||
<p><strong>URL sends are different:</strong> <code>/send <https://…></code> sends an image URL immediately as its own
|
||||
message — nothing is staged, and it isn't available in end-to-end encrypted rooms (the server
|
||||
would have to fetch the image, which would defeat the encryption).</p>
|
||||
<h2 id="attachment-kinds">Attachment kinds</h2>
|
||||
<p>The kind is detected per attachment, not per message:</p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Kind</th>
|
||||
<th>Detected by</th>
|
||||
<th>Renders as</th>
|
||||
<th>Default size limit</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><strong>Image</strong></td>
|
||||
<td>Magic bytes: JPEG, PNG, GIF, WebP</td>
|
||||
<td>ASCII-art preview in chat</td>
|
||||
<td>10 MB</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Audio</strong></td>
|
||||
<td>Extension: <code>.mp3</code> <code>.wav</code> <code>.ogg</code> <code>.flac</code> <code>.aac</code> <code>.m4a</code> <code>.wma</code></td>
|
||||
<td>Playable row (▶)</td>
|
||||
<td>10 MB</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>File</strong></td>
|
||||
<td>Everything else</td>
|
||||
<td>Downloadable row</td>
|
||||
<td>100 MB</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>Limits are per file and server-configurable — see the <code>Uploads</code> section in the
|
||||
<a href="configuration.html">configuration guide</a> (<code>MaxImageSizeMB</code>, <code>MaxAudioSizeMB</code>, <code>MaxFileSizeMB</code>,
|
||||
<code>MaxAttachmentsPerMessage</code>).</p>
|
||||
<h2 id="image-previews-ascii-art">Image previews (ASCII art)</h2>
|
||||
<p>Images are rendered in chat as half-block ASCII art. You pick the rendering size:</p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Flag</th>
|
||||
<th>Size</th>
|
||||
<th>Feel</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>-s</code> / <code>/size s</code></td>
|
||||
<td>40 × 40</td>
|
||||
<td>compact</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>-m</code> / <code>/size m</code></td>
|
||||
<td>80 × 80</td>
|
||||
<td>default</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>-l</code> / <code>/size l</code></td>
|
||||
<td>120 × 120</td>
|
||||
<td>detailed</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p><code>/size</code> with no argument opens a picker; the choice persists as your default. A one-off
|
||||
<code>-s|-m|-l</code> flag on <code>/send</code> applies to that message.</p>
|
||||
<h2 id="receiving-attachments">Receiving attachments</h2>
|
||||
<p>Right-click a message (or press <code>F6</code> to select one with the arrow keys) for actions:</p>
|
||||
<ul>
|
||||
<li><strong>Images</strong> → save to disk</li>
|
||||
<li><strong>Audio</strong> → play (in-client playback)</li>
|
||||
<li><strong>Files</strong> → download</li>
|
||||
</ul>
|
||||
<p>Downloads go to your configured download folder — set it with <code>/downloadpath</code> (no argument
|
||||
opens a native folder picker, or pass a path directly).</p>
|
||||
<h2 id="attachments-in-encrypted-rooms">Attachments in encrypted rooms</h2>
|
||||
<p>In an <a href="encrypted-rooms.html">end-to-end encrypted room</a> every attachment is encrypted
|
||||
client-side <strong>before</strong> upload:</p>
|
||||
<pre><code class="lang-mermaid">flowchart LR
|
||||
F[File bytes] -->|AES-256-GCM with room key| B[Ciphertext blob]
|
||||
F -->|if image: render ASCII locally| A[ASCII preview]
|
||||
A -->|room-encrypt| AP["$RC1$… preview"]
|
||||
B --> S[Server stores blob + name + size]
|
||||
AP --> S
|
||||
</code></pre>
|
||||
<p>The server never sees the file contents or the rendered preview — it stores an opaque blob and
|
||||
broadcasts it to members, who decrypt locally. File <strong>names and sizes remain visible</strong> to the
|
||||
server so the file list stays usable; don't put secrets in a file name. Pasted clipboard
|
||||
images go through exactly the same pipeline.</p>
|
||||
<h2 id="deleting-messages-with-attachments">Deleting messages with attachments</h2>
|
||||
<p>Deleting a message also removes its uploaded attachment files from the server. You can always
|
||||
delete your own messages; moderators can delete others' — see <a href="moderation.html">Moderation & Roles</a>.</p>
|
||||
|
||||
</article>
|
||||
|
||||
<div class="contribution d-print-none">
|
||||
<a href="https://github.com/HueByte/EchoHub/blob/master/docs/#L1" class="edit-link">Edit this page</a>
|
||||
</div>
|
||||
|
||||
<div class="next-article d-print-none border-top" id="nextArticle"></div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="affix">
|
||||
<nav id="affix"></nav>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<div class="container-xxl search-results" id="search-results"></div>
|
||||
|
||||
<footer class="border-top text-secondary">
|
||||
<div class="container-xxl">
|
||||
<div class="flex-fill">
|
||||
<div class='footer-custom'><div class='footer-inner'><span class='footer-brand'>EchoHub</span><span class='footer-sep'>·</span><a href='https://github.com/HueByte/EchoHub'>GitHub</a><span class='footer-sep'>·</span><a href='https://echohub.voidcube.cloud'>Website</a></div></div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,243 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Moderation & Roles | EchoHub Documentation </title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="title" content="Moderation & Roles | EchoHub Documentation ">
|
||||
|
||||
|
||||
<link rel="icon" href="../images/hue_icon.svg">
|
||||
<link rel="stylesheet" href="../public/docfx.min.css">
|
||||
<link rel="stylesheet" href="../public/main.css">
|
||||
<meta name="docfx:navrel" content="../toc.html">
|
||||
<meta name="docfx:tocrel" content="toc.html">
|
||||
|
||||
<meta name="docfx:rel" content="../">
|
||||
|
||||
|
||||
<meta name="docfx:docurl" content="https://github.com/HueByte/EchoHub/blob/master/docs/#L1">
|
||||
<meta name="loc:inThisArticle" content="In this article">
|
||||
<meta name="loc:searchResultsCount" content="{count} results for "{query}"">
|
||||
<meta name="loc:searchNoResults" content="No results for "{query}"">
|
||||
<meta name="loc:tocFilter" content="Filter by title">
|
||||
<meta name="loc:nextArticle" content="Next">
|
||||
<meta name="loc:prevArticle" content="Previous">
|
||||
<meta name="loc:themeLight" content="Light">
|
||||
<meta name="loc:themeDark" content="Dark">
|
||||
<meta name="loc:themeAuto" content="Auto">
|
||||
<meta name="loc:changeTheme" content="Change theme">
|
||||
<meta name="loc:copy" content="Copy">
|
||||
<meta name="loc:downloadPdf" content="Download PDF">
|
||||
|
||||
<script type="module" src="./../public/docfx.min.js"></script>
|
||||
|
||||
<script>
|
||||
const theme = localStorage.getItem('theme') || 'auto'
|
||||
document.documentElement.setAttribute('data-bs-theme', theme === 'auto' ? (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light') : theme)
|
||||
</script>
|
||||
|
||||
</head>
|
||||
|
||||
<body class="tex2jax_ignore" data-layout="" data-yaml-mime="">
|
||||
<header class="bg-body border-bottom">
|
||||
<nav id="autocollapse" class="navbar navbar-expand-md" role="navigation">
|
||||
<div class="container-xxl flex-nowrap">
|
||||
<a class="navbar-brand" href="../index.html">
|
||||
<img id="logo" class="svg" src="../images/hue_icon.svg" alt="EchoHub">
|
||||
EchoHub
|
||||
</a>
|
||||
<button class="btn btn-lg d-md-none border-0" type="button" data-bs-toggle="collapse" data-bs-target="#navpanel" aria-controls="navpanel" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<i class="bi bi-three-dots"></i>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navpanel">
|
||||
<div id="navbar">
|
||||
<form class="search" role="search" id="search">
|
||||
<i class="bi bi-search"></i>
|
||||
<input class="form-control" id="search-query" type="search" disabled placeholder="Search" autocomplete="off" aria-label="Search">
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<main class="container-xxl">
|
||||
<div class="toc-offcanvas">
|
||||
<div class="offcanvas-md offcanvas-start" tabindex="-1" id="tocOffcanvas" aria-labelledby="tocOffcanvasLabel">
|
||||
<div class="offcanvas-header">
|
||||
<h5 class="offcanvas-title" id="tocOffcanvasLabel">Table of Contents</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="offcanvas" data-bs-target="#tocOffcanvas" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="offcanvas-body">
|
||||
<nav class="toc" id="toc"></nav>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<div class="actionbar">
|
||||
<button class="btn btn-lg border-0 d-md-none" type="button" data-bs-toggle="offcanvas" data-bs-target="#tocOffcanvas" aria-controls="tocOffcanvas" aria-expanded="false" aria-label="Show table of contents">
|
||||
<i class="bi bi-list"></i>
|
||||
</button>
|
||||
|
||||
<nav id="breadcrumb"></nav>
|
||||
</div>
|
||||
|
||||
<article data-uid="">
|
||||
<h1 id="moderation--roles">Moderation & Roles</h1>
|
||||
|
||||
<p>Every EchoHub server has a four-tier role hierarchy. Moderation is <strong>strictly hierarchical</strong>:
|
||||
acting on another user requires outranking them — equal rank is never enough — and a few
|
||||
invariants protect the server owner from lockouts.</p>
|
||||
<h2 id="roles">Roles</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Role</th>
|
||||
<th>Rank</th>
|
||||
<th>Users panel glyph</th>
|
||||
<th>How it's granted</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><strong>Owner</strong></td>
|
||||
<td>3</td>
|
||||
<td>★</td>
|
||||
<td>The first account ever registered on the server</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Admin</strong></td>
|
||||
<td>2</td>
|
||||
<td>♦</td>
|
||||
<td>Assigned by the Owner</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Mod</strong></td>
|
||||
<td>1</td>
|
||||
<td>❀</td>
|
||||
<td>Assigned by an Admin or the Owner</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Member</strong></td>
|
||||
<td>0</td>
|
||||
<td>—</td>
|
||||
<td>Everyone else</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>Assign roles with <code>/role <user> <admin|mod|member></code>. Two rules apply:</p>
|
||||
<ul>
|
||||
<li>You can only assign roles <strong>strictly below your own</strong> — an Admin can promote to Mod but
|
||||
cannot create another Admin; only the Owner can.</li>
|
||||
<li><strong>Owner is not assignable and not demotable.</strong> There is exactly one Owner (the first
|
||||
account), nobody can be promoted to it, and the Owner's role can't be changed.</li>
|
||||
</ul>
|
||||
<h2 id="actions">Actions</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Command</th>
|
||||
<th>Minimum role</th>
|
||||
<th>Effect</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>/kick <user> [reason]</code></td>
|
||||
<td>Mod</td>
|
||||
<td>Disconnects the user. Not persistent — they can reconnect immediately.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>/ban <user> [reason]</code></td>
|
||||
<td>Admin</td>
|
||||
<td>Persistent: flags the account banned and disconnects it. Banned accounts are rejected at login.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>/unban <user></code></td>
|
||||
<td>Admin</td>
|
||||
<td>Lifts a ban.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>/mute <user> [minutes]</code></td>
|
||||
<td>Mod</td>
|
||||
<td>Blocks the user from sending messages or uploading files. Without a duration the mute is <strong>indefinite</strong>; with one it auto-expires (checked every ~15 seconds).</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>/unmute <user></code></td>
|
||||
<td>Mod</td>
|
||||
<td>Lifts a mute early.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>/role <user> <role></code></td>
|
||||
<td>Admin</td>
|
||||
<td>Assign a role (see rules above).</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>/nuke</code></td>
|
||||
<td>Mod</td>
|
||||
<td>Deletes the <strong>entire history of the current channel</strong>, including all attachment files on disk. Channel-wide — no per-user check.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>Kick, ban, and mute all enforce the hierarchy: the target's role must be <strong>strictly lower</strong>
|
||||
than yours. A Mod cannot kick another Mod; nobody can kick, ban, mute, or demote the Owner.</p>
|
||||
<h2 id="deleting-messages">Deleting messages</h2>
|
||||
<p>Deletion has its own, slightly different rule set:</p>
|
||||
<ul>
|
||||
<li><strong>Your own messages</strong> — always deletable, whatever your role. Right-click a message →
|
||||
<em>Delete message</em>, or press <code>F6</code>, pick the message, and hit <code>Delete</code>.</li>
|
||||
<li><strong>Someone else's messages</strong> — requires <strong>Mod or higher</strong> <em>and</em> strictly outranking the
|
||||
author. A Mod can delete a Member's message, but not another Mod's.</li>
|
||||
</ul>
|
||||
<p>Deleting a message also purges its uploaded attachment blobs from the server's disk, and the
|
||||
removal is broadcast live — the message disappears from everyone's chat immediately.</p>
|
||||
<h2 id="how-actions-surface">How actions surface</h2>
|
||||
<p>Everyone in the channel sees moderation happen:</p>
|
||||
<ul>
|
||||
<li><strong>TUI clients</strong> show system messages — <em>"alice was kicked (reason)"</em>, <em>"bob was banned"</em>,
|
||||
<em>"Channel history has been cleared by a moderator."</em> The kicked or banned user themselves
|
||||
gets a dialog with the reason, then the client disconnects.</li>
|
||||
<li><strong>IRC clients</strong> get native protocol events: kicks arrive as a real <code>KICK</code> command, bans as
|
||||
a server <code>NOTICE</code>. (See the <a href="irc-gateway.html">IRC Gateway guide</a>.)</li>
|
||||
</ul>
|
||||
<p>Muted users aren't announced; they simply receive <em>"You are muted and cannot send messages."</em>
|
||||
when they try to speak.</p>
|
||||
<h2 id="design-notes">Design notes</h2>
|
||||
<ul>
|
||||
<li>All checks run server-side in the moderation API — the client commands are conveniences,
|
||||
and the same rules bind IRC users and any direct API caller.</li>
|
||||
<li>Bans are account-level, not IP-level. A banned person can register a fresh account; pair
|
||||
bans with registration hygiene on public servers.</li>
|
||||
<li>In <a href="encrypted-rooms.html">end-to-end encrypted rooms</a> moderation still works at the metadata
|
||||
level — messages can be deleted and users muted/kicked by identity — but no moderator can
|
||||
<em>read</em> the content, including the Owner.</li>
|
||||
</ul>
|
||||
|
||||
</article>
|
||||
|
||||
<div class="contribution d-print-none">
|
||||
<a href="https://github.com/HueByte/EchoHub/blob/master/docs/#L1" class="edit-link">Edit this page</a>
|
||||
</div>
|
||||
|
||||
<div class="next-article d-print-none border-top" id="nextArticle"></div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="affix">
|
||||
<nav id="affix"></nav>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<div class="container-xxl search-results" id="search-results"></div>
|
||||
|
||||
<footer class="border-top text-secondary">
|
||||
<div class="container-xxl">
|
||||
<div class="flex-fill">
|
||||
<div class='footer-custom'><div class='footer-inner'><span class='footer-brand'>EchoHub</span><span class='footer-sep'>·</span><a href='https://github.com/HueByte/EchoHub'>GitHub</a><span class='footer-sep'>·</span><a href='https://echohub.voidcube.cloud'>Website</a></div></div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
@@ -20,6 +20,18 @@
|
||||
<li>
|
||||
<a href="getting-started.html" name="" title="Getting Started">Getting Started</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="tui-guide.html" name="" title="TUI Guide">TUI Guide</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="messages-and-attachments.html" name="" title="Messages & Attachments">Messages & Attachments</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="moderation.html" name="" title="Moderation & Roles">Moderation & Roles</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="irc-gateway.html" name="" title="IRC Gateway">IRC Gateway</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="docker.html" name="" title="Docker">Docker</a>
|
||||
</li>
|
||||
|
||||
+1
-1
@@ -1,2 +1,2 @@
|
||||
|
||||
{"items":[{"name":"Guides","items":[{"name":"Getting Started","href":"getting-started.html","topicHref":"getting-started.html"},{"name":"Docker","href":"docker.html","topicHref":"docker.html"},{"name":"Architecture","href":"architecture.html","topicHref":"architecture.html"},{"name":"Configuration","href":"configuration.html","topicHref":"configuration.html"},{"name":"Encryption","href":"encryption.html","topicHref":"encryption.html"},{"name":"Encrypted Rooms","href":"encrypted-rooms.html","topicHref":"encrypted-rooms.html"},{"name":"Notification Sounds","href":"notification-sounds.html","topicHref":"notification-sounds.html"}]},{"name":"Flows","includedFrom":"~/flows/toc.yml","items":[{"name":"Authentication","href":"../flows/authentication.html","topicHref":"../flows/authentication.html"},{"name":"Connection","href":"../flows/connection.html","topicHref":"../flows/connection.html"},{"name":"Messaging","href":"../flows/messaging.html","topicHref":"../flows/messaging.html"},{"name":"Channels","href":"../flows/channels.html","topicHref":"../flows/channels.html"},{"name":"Moderation","href":"../flows/moderation.html","topicHref":"../flows/moderation.html"},{"name":"Media & Services","href":"../flows/media.html","topicHref":"../flows/media.html"}]}]}
|
||||
{"items":[{"name":"Guides","items":[{"name":"Getting Started","href":"getting-started.html","topicHref":"getting-started.html"},{"name":"TUI Guide","href":"tui-guide.html","topicHref":"tui-guide.html"},{"name":"Messages & Attachments","href":"messages-and-attachments.html","topicHref":"messages-and-attachments.html"},{"name":"Moderation & Roles","href":"moderation.html","topicHref":"moderation.html"},{"name":"IRC Gateway","href":"irc-gateway.html","topicHref":"irc-gateway.html"},{"name":"Docker","href":"docker.html","topicHref":"docker.html"},{"name":"Architecture","href":"architecture.html","topicHref":"architecture.html"},{"name":"Configuration","href":"configuration.html","topicHref":"configuration.html"},{"name":"Encryption","href":"encryption.html","topicHref":"encryption.html"},{"name":"Encrypted Rooms","href":"encrypted-rooms.html","topicHref":"encrypted-rooms.html"},{"name":"Notification Sounds","href":"notification-sounds.html","topicHref":"notification-sounds.html"}]},{"name":"Flows","includedFrom":"~/flows/toc.yml","items":[{"name":"Authentication","href":"../flows/authentication.html","topicHref":"../flows/authentication.html"},{"name":"Connection","href":"../flows/connection.html","topicHref":"../flows/connection.html"},{"name":"Messaging","href":"../flows/messaging.html","topicHref":"../flows/messaging.html"},{"name":"Channels","href":"../flows/channels.html","topicHref":"../flows/channels.html"},{"name":"Moderation","href":"../flows/moderation.html","topicHref":"../flows/moderation.html"},{"name":"Media & Services","href":"../flows/media.html","topicHref":"../flows/media.html"}]}]}
|
||||
|
||||
@@ -0,0 +1,314 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>TUI Guide | EchoHub Documentation </title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="title" content="TUI Guide | EchoHub Documentation ">
|
||||
|
||||
|
||||
<link rel="icon" href="../images/hue_icon.svg">
|
||||
<link rel="stylesheet" href="../public/docfx.min.css">
|
||||
<link rel="stylesheet" href="../public/main.css">
|
||||
<meta name="docfx:navrel" content="../toc.html">
|
||||
<meta name="docfx:tocrel" content="toc.html">
|
||||
|
||||
<meta name="docfx:rel" content="../">
|
||||
|
||||
|
||||
<meta name="docfx:docurl" content="https://github.com/HueByte/EchoHub/blob/master/docs/#L1">
|
||||
<meta name="loc:inThisArticle" content="In this article">
|
||||
<meta name="loc:searchResultsCount" content="{count} results for "{query}"">
|
||||
<meta name="loc:searchNoResults" content="No results for "{query}"">
|
||||
<meta name="loc:tocFilter" content="Filter by title">
|
||||
<meta name="loc:nextArticle" content="Next">
|
||||
<meta name="loc:prevArticle" content="Previous">
|
||||
<meta name="loc:themeLight" content="Light">
|
||||
<meta name="loc:themeDark" content="Dark">
|
||||
<meta name="loc:themeAuto" content="Auto">
|
||||
<meta name="loc:changeTheme" content="Change theme">
|
||||
<meta name="loc:copy" content="Copy">
|
||||
<meta name="loc:downloadPdf" content="Download PDF">
|
||||
|
||||
<script type="module" src="./../public/docfx.min.js"></script>
|
||||
|
||||
<script>
|
||||
const theme = localStorage.getItem('theme') || 'auto'
|
||||
document.documentElement.setAttribute('data-bs-theme', theme === 'auto' ? (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light') : theme)
|
||||
</script>
|
||||
|
||||
</head>
|
||||
|
||||
<body class="tex2jax_ignore" data-layout="" data-yaml-mime="">
|
||||
<header class="bg-body border-bottom">
|
||||
<nav id="autocollapse" class="navbar navbar-expand-md" role="navigation">
|
||||
<div class="container-xxl flex-nowrap">
|
||||
<a class="navbar-brand" href="../index.html">
|
||||
<img id="logo" class="svg" src="../images/hue_icon.svg" alt="EchoHub">
|
||||
EchoHub
|
||||
</a>
|
||||
<button class="btn btn-lg d-md-none border-0" type="button" data-bs-toggle="collapse" data-bs-target="#navpanel" aria-controls="navpanel" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<i class="bi bi-three-dots"></i>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navpanel">
|
||||
<div id="navbar">
|
||||
<form class="search" role="search" id="search">
|
||||
<i class="bi bi-search"></i>
|
||||
<input class="form-control" id="search-query" type="search" disabled placeholder="Search" autocomplete="off" aria-label="Search">
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<main class="container-xxl">
|
||||
<div class="toc-offcanvas">
|
||||
<div class="offcanvas-md offcanvas-start" tabindex="-1" id="tocOffcanvas" aria-labelledby="tocOffcanvasLabel">
|
||||
<div class="offcanvas-header">
|
||||
<h5 class="offcanvas-title" id="tocOffcanvasLabel">Table of Contents</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="offcanvas" data-bs-target="#tocOffcanvas" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="offcanvas-body">
|
||||
<nav class="toc" id="toc"></nav>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<div class="actionbar">
|
||||
<button class="btn btn-lg border-0 d-md-none" type="button" data-bs-toggle="offcanvas" data-bs-target="#tocOffcanvas" aria-controls="tocOffcanvas" aria-expanded="false" aria-label="Show table of contents">
|
||||
<i class="bi bi-list"></i>
|
||||
</button>
|
||||
|
||||
<nav id="breadcrumb"></nav>
|
||||
</div>
|
||||
|
||||
<article data-uid="">
|
||||
<h1 id="tui-guide">TUI Guide</h1>
|
||||
|
||||
<p>Everything you can do in the EchoHub terminal client: keyboard shortcuts, mouse actions,
|
||||
slash commands, themes, and the everyday behaviors (unread markers, auto-join, scrollback)
|
||||
that make it feel like a proper IRC-era client with modern comforts.</p>
|
||||
<h2 id="layout">Layout</h2>
|
||||
<pre><code class="lang-text">┌ Menu bar ──────────────────────────────────────────────────┐
|
||||
│ ┌ Channels ─┐ ┌ Messages ────────────────────┐ ┌ Users ──┐ │
|
||||
│ │ #general 3│ │ 12:01 <alice> hi │ │ ★ alice │ │
|
||||
│ │ #dev │ │ ── new messages ── │ │ ❀ bob │ │
|
||||
│ │ #random*~ │ │ 12:04 <bob> anyone around? │ │ carol │ │
|
||||
│ └───────────┘ └──────────────────────────────┘ │ d [irc] │ │
|
||||
│ ┌ Message │ Enter=send │ Tab=complete │ … ────┐ └─────────┘ │
|
||||
│ │ _ │ │
|
||||
│ └─────────────────────────────────────────────┘ │
|
||||
│ Status: Connected │ v0.2.14 │ alice │ Act: #dev │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
</code></pre>
|
||||
<p>Channel list markers: <code>*</code> = password-protected, <code>~</code> = private (unlisted), plus unread counts
|
||||
(orange when you were @mentioned). Users panel glyphs: <code>★</code> Owner, <code>♦</code> Admin, <code>❀</code> Mod,
|
||||
<code>[irc]</code> for IRC-gateway-only users; status icons <code>●</code>/<code>○</code>/<code>◐</code>/<code>◌</code> for online/offline/away/dnd.</p>
|
||||
<h2 id="keyboard-shortcuts">Keyboard shortcuts</h2>
|
||||
<h3 id="in-the-message-input">In the message input</h3>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Key</th>
|
||||
<th>Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>Enter</code></td>
|
||||
<td>Send the message (also sends staged attachments with the text as caption)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>Ctrl+N</code></td>
|
||||
<td>Insert a newline (multiline message)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>Tab</code></td>
|
||||
<td>Autocomplete a slash command (<code>/th</code> → <code>/theme</code>)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>Ctrl+V</code> (or <code>Ctrl+Y</code>)</td>
|
||||
<td>Paste — copied files and images become attachments, text pastes normally (<a href="messages-and-attachments.html">details</a>)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>Ctrl+C</code> / <code>Ctrl+X</code></td>
|
||||
<td>Copy / cut in the input</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>Ctrl+W</code></td>
|
||||
<td>Delete the word left of the cursor</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>Ctrl+K</code></td>
|
||||
<td>Open the search palette</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>F6</code></td>
|
||||
<td>Move focus into the message list</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h3 id="in-the-message-list-after-f6">In the message list (after <code>F6</code>)</h3>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Key</th>
|
||||
<th>Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>↑</code> / <code>↓</code></td>
|
||||
<td>Select a message</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>Enter</code></td>
|
||||
<td>Activate: play/download/save an attachment, open an <code>@mention</code>'s profile, join a <code>#channel</code>, or open the sender's profile</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>Delete</code> / <code>Backspace</code></td>
|
||||
<td>Delete the selected message (with confirmation; <a href="moderation.html">permission rules</a>)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>F6</code></td>
|
||||
<td>Return focus to the input</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h3 id="anywhere">Anywhere</h3>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Key</th>
|
||||
<th>Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>F2</code></td>
|
||||
<td>Toggle the users panel</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>Ctrl+K</code></td>
|
||||
<td>Search palette</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>Alt+Q</code></td>
|
||||
<td>Quit</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h2 id="the-search-palette-ctrlk">The search palette (<code>Ctrl+K</code>)</h2>
|
||||
<p>A command-palette that searches <strong>channels and app actions</strong> — type to filter, <code>↓</code> to
|
||||
navigate, <code>Enter</code> to jump. Actions include Connect, Disconnect, Logout, My Profile,
|
||||
Set Status, Create/Delete Channel, Saved Servers, Toggle Users Panel, Check for Updates,
|
||||
and Quit. <code>Ctrl+K</code> again closes it.</p>
|
||||
<h2 id="mouse">Mouse</h2>
|
||||
<ul>
|
||||
<li><strong>Right-click a message</strong> for the context menu: save image / play audio / download file
|
||||
(depending on the attachment), *Mention @user*, <em>View profile</em>, <em>Copy text</em>,
|
||||
<em>Copy message ID</em>, <em>Delete message</em>.</li>
|
||||
<li><strong>Left-click a message</strong> does the most useful thing for that line: attachments
|
||||
play/download/save, <code>@mentions</code> and the sender open profiles, <code>#channel</code> references join
|
||||
that channel.</li>
|
||||
<li><strong>Click a user</strong> in the users panel to open their profile; <strong>click a channel</strong> to switch.</li>
|
||||
</ul>
|
||||
<h2 id="slash-commands">Slash commands</h2>
|
||||
<p>Type <code>/help</code> in any channel for the full list. The highlights:</p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Command</th>
|
||||
<th>What it does</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>/status <online\|away\|dnd\|invisible></code> or <code>/status <message></code></td>
|
||||
<td>Presence / status message</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>/nick <name></code>, <code>/color <#hex></code>, <code>/avatar <url or path></code></td>
|
||||
<td>Display name, nick color, avatar</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>/theme <name></code></td>
|
||||
<td>Switch theme</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>/send</code>, <code>/clear</code>, <code>/size</code>, <code>/downloadpath</code></td>
|
||||
<td>Attachments — see <a href="messages-and-attachments.html">Messages & Attachments</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>/join <channel> [password]</code>, <code>/leave</code>, <code>/topic <text></code></td>
|
||||
<td>Channel membership and topic</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>/passwd <old> <new></code></td>
|
||||
<td>Rotate an encrypted room's passphrase</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>/profile [user]</code>, <code>/users</code>, <code>/meta</code></td>
|
||||
<td>Profiles, online users, room info</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>/kick</code>, <code>/ban</code>, <code>/mute</code>, <code>/role</code>, <code>/nuke</code>, …</td>
|
||||
<td><a href="moderation.html">Moderation</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>/servers</code>, <code>/quit</code></td>
|
||||
<td>Saved servers, exit</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>Emoji shortcodes (<code>:smile:</code> style) are replaced live as you type.</p>
|
||||
<h2 id="themes">Themes</h2>
|
||||
<p>14 built-in themes: <strong>Default, Transparent, TransparentLight, Classic, Light, Hacker,
|
||||
Solarized, Dracula, Monokai, Nord, Gruvbox, Ocean, HighContrast, RosePine</strong> — switch from
|
||||
the User menu or <code>/theme <name></code>. The two <em>Transparent</em> themes use no background color at
|
||||
all, so your terminal's own background (and any blur/acrylic) shows through.</p>
|
||||
<p>You can add your own: drop a theme JSON into <code>~/.echohub/themes/</code> and it appears in the list
|
||||
(names that collide with a built-in are skipped).</p>
|
||||
<h2 id="everyday-behaviors">Everyday behaviors</h2>
|
||||
<ul>
|
||||
<li><strong>Unread markers</strong> — a <code>── new messages ──</code> rule marks where you left off in each channel,
|
||||
irssi-style. Read positions are <strong>persisted per server</strong>, so the marker survives
|
||||
reconnects and restarts. The status bar's <code>Act:</code> segment lists channels with activity
|
||||
(orange when you were @mentioned), and day boundaries draw a date rule.</li>
|
||||
<li><strong>Auto-join</strong> — connecting joins <code>#general</code> plus every channel you're a member of, so
|
||||
unread counts and mentions accumulate everywhere. Channels you <code>/leave</code> stay left, and
|
||||
password-protected or <a href="encrypted-rooms.html">encrypted rooms</a> are never auto-prompted —
|
||||
join those explicitly. <code>#general</code> is the home channel and can't be left or deleted.</li>
|
||||
<li><strong>Scrollback</strong> — history loads 100 messages at a time; scrolling to the top of a channel
|
||||
fetches the next page and keeps your position (no jump).</li>
|
||||
<li><strong>Drag & drop</strong> — dropping a file onto the window stages it as an attachment.</li>
|
||||
</ul>
|
||||
|
||||
</article>
|
||||
|
||||
<div class="contribution d-print-none">
|
||||
<a href="https://github.com/HueByte/EchoHub/blob/master/docs/#L1" class="edit-link">Edit this page</a>
|
||||
</div>
|
||||
|
||||
<div class="next-article d-print-none border-top" id="nextArticle"></div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="affix">
|
||||
<nav id="affix"></nav>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<div class="container-xxl search-results" id="search-results"></div>
|
||||
|
||||
<footer class="border-top text-secondary">
|
||||
<div class="container-xxl">
|
||||
<div class="flex-fill">
|
||||
<div class='footer-custom'><div class='footer-inner'><span class='footer-brand'>EchoHub</span><span class='footer-sep'>·</span><a href='https://github.com/HueByte/EchoHub'>GitHub</a><span class='footer-sep'>·</span><a href='https://echohub.voidcube.cloud'>Website</a></div></div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user