564 lines
17 KiB
HTML
564 lines
17 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta
|
|
name="viewport"
|
|
content="width=device-width,initial-scale=1,viewport-fit=cover"
|
|
>
|
|
<meta name="theme-color" content="#0f1012">
|
|
<meta name="color-scheme" content="dark">
|
|
<meta name="referrer" content="same-origin">
|
|
<title>pre.v1</title>
|
|
<link
|
|
rel="stylesheet"
|
|
href="{{ url_for('static', filename='style.css', v=asset_version) }}"
|
|
>
|
|
</head>
|
|
<body>
|
|
<div class="app-shell">
|
|
<header class="chat-header">
|
|
<div class="header-inner">
|
|
<div class="header-brand">
|
|
<span
|
|
id="presenceDot"
|
|
class="header-dot"
|
|
aria-hidden="true"
|
|
></span>
|
|
|
|
<div class="header-room-copy">
|
|
<div id="headerTitle" class="header-title">Feed</div>
|
|
<div id="headerSubtitle" class="header-subtitle">Recent activity</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="header-navigation">
|
|
<button
|
|
id="feedButton"
|
|
class="header-action feed-button active"
|
|
type="button"
|
|
aria-label="Open activity feed"
|
|
aria-pressed="true"
|
|
>
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24">
|
|
<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 6h13M8 12h13M8 18h13M3 6h.01M3 12h.01M3 18h.01"/>
|
|
</svg>
|
|
</button>
|
|
|
|
<button
|
|
id="pagesButton"
|
|
class="header-action pages-button"
|
|
type="button"
|
|
aria-label="Open team pages"
|
|
aria-pressed="false"
|
|
>
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24">
|
|
<g fill="none">
|
|
<path d="M3.5 2.5h17v19h-17z"/>
|
|
<path stroke="currentColor" stroke-linecap="square" stroke-width="2" d="M3.5 2.5h17v19h-17zM8 8h8m-8 4h8m-8 4h5"/>
|
|
</g>
|
|
</svg>
|
|
</button>
|
|
|
|
<button
|
|
id="dmsButton"
|
|
class="header-action"
|
|
type="button"
|
|
aria-label="Open direct messages"
|
|
aria-pressed="false"
|
|
title="Direct messages"
|
|
>
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24">
|
|
<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/>
|
|
</svg>
|
|
</button>
|
|
|
|
<button
|
|
id="backButton"
|
|
class="header-action hidden"
|
|
type="button"
|
|
aria-label="Go back"
|
|
>
|
|
Back
|
|
</button>
|
|
|
|
<select
|
|
id="teamSelect"
|
|
class="room-select team-select"
|
|
aria-label="Select team"
|
|
disabled
|
|
>
|
|
<option value="">Loading teams…</option>
|
|
</select>
|
|
|
|
<select
|
|
id="roomSelect"
|
|
class="room-select channel-select"
|
|
aria-label="Select channel"
|
|
disabled
|
|
>
|
|
<option value="">Loading channels…</option>
|
|
</select>
|
|
|
|
<div id="presenceLabel" class="presence-label hidden" aria-live="polite"></div>
|
|
|
|
<button
|
|
id="settingsButton"
|
|
class="header-action"
|
|
type="button"
|
|
aria-label="Open settings and profile menu"
|
|
title="Settings and profile"
|
|
>
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24">
|
|
<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 3l2.3.8l2.4-.5l1.3 2.1l2.2 1l-.3 2.4l1.1 2.1l-1.6 1.8l-.3 2.4l-2.4.5L14 21l-2-.8l-2 .8l-1.4-2.1l-2.4-.5l-.3-2.4L4.3 14l1.1-2.1l-.3-2.4l2.2-1l1.3-2.1l2.4.5zM12 15.5A3.5 3.5 0 1 0 12 8.5a3.5 3.5 0 0 0 0 7z"/>
|
|
</svg>
|
|
</button>
|
|
|
|
<button
|
|
id="callStatusChip"
|
|
class="header-action call-status-chip"
|
|
type="button"
|
|
aria-label="Open call panel"
|
|
title="Voice call"
|
|
>
|
|
Call
|
|
</button>
|
|
</div>
|
|
|
|
<div class="header-account-wrap">
|
|
<div id="headerAccount" class="header-account">not signed in</div>
|
|
|
|
<button
|
|
id="logoutButton"
|
|
class="header-action hidden"
|
|
type="button"
|
|
aria-label="Sign out"
|
|
title="Sign out"
|
|
>
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24">
|
|
<path fill="none" stroke="currentColor" stroke-linecap="square" stroke-width="2" d="M15.5 16.5L20 12l-4.5-4.5m3.25 4.5H9m0 8.5H4v-17h5"/>
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</header>
|
|
|
|
<main
|
|
id="feedBox"
|
|
class="feed-box"
|
|
aria-live="polite"
|
|
aria-busy="true"
|
|
aria-label="Activity feed"
|
|
>
|
|
<div class="empty-state">
|
|
<div class="empty-card">Loading activity…</div>
|
|
</div>
|
|
</main>
|
|
|
|
<main
|
|
id="dmBox"
|
|
class="dm-box hidden"
|
|
aria-live="polite"
|
|
aria-busy="false"
|
|
aria-label="Direct messages"
|
|
>
|
|
<div class="empty-state">
|
|
<div class="empty-card">Sign in to view direct messages.</div>
|
|
</div>
|
|
</main>
|
|
|
|
<main
|
|
id="chatBox"
|
|
class="chat-box hidden"
|
|
aria-live="off"
|
|
aria-busy="true"
|
|
aria-label="Channel messages"
|
|
></main>
|
|
|
|
<main
|
|
id="threadBox"
|
|
class="thread-box hidden"
|
|
aria-live="off"
|
|
aria-busy="false"
|
|
aria-label="Message thread"
|
|
></main>
|
|
|
|
<main
|
|
id="pagesBox"
|
|
class="pages-box hidden"
|
|
aria-live="polite"
|
|
aria-busy="false"
|
|
aria-label="Team pages"
|
|
></main>
|
|
|
|
<main
|
|
id="pageDetailBox"
|
|
class="page-detail-box hidden"
|
|
aria-live="polite"
|
|
aria-busy="false"
|
|
aria-label="Page details"
|
|
></main>
|
|
|
|
<main
|
|
id="profileBox"
|
|
class="profile-box hidden"
|
|
aria-live="polite"
|
|
aria-busy="false"
|
|
aria-label="Profile"
|
|
></main>
|
|
|
|
<div id="newMessagesBar" class="new-messages-bar hidden">
|
|
<button id="jumpToLatestButton" class="small-button" type="button">
|
|
New messages · Jump to latest
|
|
</button>
|
|
</div>
|
|
|
|
<div id="typingBar" class="typing-bar hidden" aria-live="polite"></div>
|
|
|
|
<div id="composerWrap" class="composer-wrap hidden">
|
|
<form id="chatForm" class="composer">
|
|
<label class="sr-only" for="messageInput">Message</label>
|
|
|
|
<div class="composer-field-wrap">
|
|
<textarea
|
|
id="messageInput"
|
|
class="composer-input"
|
|
rows="1"
|
|
maxlength="1000"
|
|
autocomplete="off"
|
|
placeholder="sign in to send"
|
|
aria-label="Message"
|
|
disabled
|
|
></textarea>
|
|
|
|
<div class="composer-meta">
|
|
<span id="attachmentName" class="attachment-name"></span>
|
|
<span id="messageCount" class="message-count">0 / 1000</span>
|
|
</div>
|
|
</div>
|
|
|
|
<label
|
|
id="attachmentButton"
|
|
class="attachment-button disabled"
|
|
for="attachmentInput"
|
|
title="Attach file(s)"
|
|
aria-label="Attach file(s)"
|
|
>
|
|
+
|
|
</label>
|
|
|
|
<input
|
|
id="attachmentInput"
|
|
class="sr-only"
|
|
type="file"
|
|
accept=".txt,.pdf,.png,.jpg,.jpeg,.gif,.webp"
|
|
multiple
|
|
disabled
|
|
>
|
|
|
|
<button id="sendButton" class="send-button" type="submit" disabled>
|
|
Send
|
|
</button>
|
|
</form>
|
|
</div>
|
|
|
|
<div id="threadComposerWrap" class="composer-wrap hidden">
|
|
<form id="threadForm" class="composer">
|
|
<label class="sr-only" for="threadInput">Reply in thread</label>
|
|
|
|
<div class="composer-field-wrap">
|
|
<textarea
|
|
id="threadInput"
|
|
class="composer-input"
|
|
rows="1"
|
|
maxlength="1000"
|
|
autocomplete="off"
|
|
placeholder="reply in thread"
|
|
aria-label="Reply in thread"
|
|
disabled
|
|
></textarea>
|
|
|
|
<div class="composer-meta">
|
|
<span id="threadAttachmentName" class="attachment-name"></span>
|
|
<span id="threadMessageCount" class="message-count">0 / 1000</span>
|
|
</div>
|
|
</div>
|
|
|
|
<label
|
|
id="threadAttachmentButton"
|
|
class="attachment-button disabled"
|
|
for="threadAttachmentInput"
|
|
title="Attach file(s)"
|
|
aria-label="Attach file(s)"
|
|
>
|
|
+
|
|
</label>
|
|
|
|
<input
|
|
id="threadAttachmentInput"
|
|
class="sr-only"
|
|
type="file"
|
|
accept=".txt,.pdf,.png,.jpg,.jpeg,.gif,.webp"
|
|
multiple
|
|
disabled
|
|
>
|
|
|
|
<button id="threadSendButton" class="send-button" type="submit" disabled>
|
|
Reply
|
|
</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<section
|
|
id="authOverlay"
|
|
class="auth-overlay"
|
|
role="dialog"
|
|
aria-modal="true"
|
|
aria-label="Account access"
|
|
>
|
|
<div class="auth-card">
|
|
<p></p>
|
|
|
|
<div id="authNotice" class="notice" role="status"></div>
|
|
|
|
<label class="sr-only" for="accessKeyInput">access key</label>
|
|
<input
|
|
id="accessKeyInput"
|
|
class="field"
|
|
type="password"
|
|
autocomplete="one-time-code"
|
|
autocapitalize="none"
|
|
spellcheck="false"
|
|
maxlength="256"
|
|
placeholder="access key"
|
|
>
|
|
|
|
<label class="sr-only" for="usernameInput">Username</label>
|
|
<input
|
|
id="usernameInput"
|
|
class="field"
|
|
type="text"
|
|
autocomplete="username"
|
|
autocapitalize="none"
|
|
spellcheck="false"
|
|
maxlength="30"
|
|
placeholder="username"
|
|
>
|
|
|
|
<label class="sr-only" for="passwordInput">Password</label>
|
|
<input
|
|
id="passwordInput"
|
|
class="field"
|
|
type="password"
|
|
autocomplete="current-password"
|
|
maxlength="256"
|
|
placeholder="password"
|
|
>
|
|
|
|
<div class="auth-actions">
|
|
<button id="loginButton" class="button" type="button">sign in</button>
|
|
<button id="registerButton" class="button secondary" type="button">create account</button>
|
|
</div>
|
|
|
|
<p class="auth-help"></p>
|
|
</div>
|
|
</section>
|
|
|
|
<section
|
|
id="blockedOverlay"
|
|
class="blocked-overlay hidden"
|
|
role="alertdialog"
|
|
aria-modal="true"
|
|
aria-label="Access blocked"
|
|
>
|
|
<div class="auth-card">
|
|
<h1>Access blocked</h1>
|
|
<p id="blockedMessage">Access is unavailable.</p>
|
|
</div>
|
|
</section>
|
|
|
|
<section
|
|
id="headerMenuOverlay"
|
|
class="header-menu-overlay hidden"
|
|
role="dialog"
|
|
aria-modal="true"
|
|
aria-label="Header menu"
|
|
>
|
|
<div class="header-menu-card">
|
|
<div class="header-menu-title">Quick actions</div>
|
|
<div id="headerMenuList" class="header-menu-list"></div>
|
|
</div>
|
|
</section>
|
|
|
|
<section
|
|
id="reactionPopupOverlay"
|
|
class="reaction-popup-overlay hidden"
|
|
role="dialog"
|
|
aria-modal="true"
|
|
aria-label="Reactions"
|
|
>
|
|
<div class="reaction-popup-card">
|
|
<h2 class="reaction-popup-title">Reactions</h2>
|
|
<div id="reactionPopupGrid" class="reaction-popup-grid"></div>
|
|
|
|
<div class="reaction-popup-custom">
|
|
<input
|
|
id="reactionCustomInput"
|
|
class="field reaction-custom-input"
|
|
type="text"
|
|
maxlength="16"
|
|
placeholder="Custom emoji"
|
|
aria-label="Custom reaction"
|
|
>
|
|
<button
|
|
id="reactionCustomButton"
|
|
class="button secondary"
|
|
type="button"
|
|
>
|
|
Add
|
|
</button>
|
|
</div>
|
|
|
|
<div id="reactionPopupList" class="reaction-popup-list"></div>
|
|
|
|
<div class="dialog-actions">
|
|
<button id="closeReactionPopupButton" class="button secondary" type="button">Close</button>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<section
|
|
id="mediaOverlay"
|
|
class="media-overlay hidden"
|
|
role="dialog"
|
|
aria-modal="true"
|
|
aria-label="Media preview"
|
|
>
|
|
<div class="media-card">
|
|
<div class="media-header">
|
|
<div id="mediaTitle" class="media-title">Media</div>
|
|
<div class="settings-actions">
|
|
<a id="mediaDownloadLink" class="button secondary" href="#" download>Download</a>
|
|
<button id="closeMediaButton" class="button secondary" type="button">Close</button>
|
|
</div>
|
|
</div>
|
|
<div class="media-body">
|
|
<img id="mediaImage" class="hidden" alt="">
|
|
<audio id="mediaAudio" class="hidden" controls preload="metadata"></audio>
|
|
<video id="mediaVideo" class="hidden" controls preload="metadata"></video>
|
|
<div id="mediaFileFallback" class="media-file-fallback hidden">
|
|
<p>This file cannot be previewed here.</p>
|
|
<a id="mediaFallbackLink" class="button" href="#" target="_blank" rel="noopener noreferrer">Open file</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<section
|
|
id="callOverlay"
|
|
class="call-overlay hidden"
|
|
role="dialog"
|
|
aria-modal="true"
|
|
aria-label="Voice call"
|
|
>
|
|
<div class="call-card">
|
|
<div class="call-title-row">
|
|
<div>
|
|
<div class="call-title">call</div>
|
|
<div id="callStatus" class="call-status">Idle</div>
|
|
</div>
|
|
<button id="closeCallPanelButton" class="button secondary" type="button">Hide</button>
|
|
</div>
|
|
|
|
<div id="callPeerLabel" class="call-peer-label">No active call</div>
|
|
|
|
<div id="callParticipants" class="call-participants"></div>
|
|
<div id="callPendingInvites" class="call-pending-invites hidden"></div>
|
|
<div id="remoteAudioContainer" class="remote-audio-container"></div>
|
|
|
|
<div class="call-actions">
|
|
<button id="startCallButton" class="button" type="button">Start call</button>
|
|
<button id="retryCallButton" class="button secondary hidden" type="button">Retry connection</button>
|
|
<button id="addToCallButton" class="button secondary hidden" type="button">Add user</button>
|
|
<button id="muteCallButton" class="button secondary hidden" type="button">Mute</button>
|
|
<button id="hangupCallButton" class="danger-button hidden" type="button">Leave call</button>
|
|
<button id="endCallButton" class="danger-button hidden" type="button">End call</button>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<button
|
|
id="adminFab"
|
|
class="admin-fab"
|
|
type="button"
|
|
aria-label="Open moderation controls"
|
|
title="Moderation controls"
|
|
>
|
|
#
|
|
</button>
|
|
|
|
<section
|
|
id="adminPanel"
|
|
class="admin-panel"
|
|
role="dialog"
|
|
aria-modal="true"
|
|
aria-label="Moderation panel"
|
|
aria-hidden="true"
|
|
>
|
|
<div class="admin-sheet">
|
|
<div class="admin-sheet-header">
|
|
<div>
|
|
<strong>Moderation</strong>
|
|
<div class="header-subtitle"></div>
|
|
</div>
|
|
|
|
<button id="closeAdminButton" class="button secondary" type="button">
|
|
Close
|
|
</button>
|
|
</div>
|
|
|
|
<div class="admin-actions">
|
|
<button id="createRoomButton" class="button" type="button">Add chat</button>
|
|
<button id="clearMessagesButton" class="danger-button" type="button">Clear selected room</button>
|
|
<button id="typingToggleButton" class="button secondary" type="button">Typing indicator: on</button>
|
|
<button id="notificationsToggleButton" class="button secondary" type="button">Notifications: off</button>
|
|
<button id="themeButton" class="button secondary" type="button" aria-label="Choose accent color">Accent color</button>
|
|
</div>
|
|
|
|
<div id="adminRooms" class="admin-rooms"></div>
|
|
<div id="adminUsers" class="admin-users"></div>
|
|
</div>
|
|
</section>
|
|
|
|
<section
|
|
id="dialogOverlay"
|
|
class="dialog-overlay hidden"
|
|
role="dialog"
|
|
aria-modal="true"
|
|
aria-labelledby="dialogTitle"
|
|
>
|
|
<div class="dialog-card">
|
|
<h2 id="dialogTitle">Confirm</h2>
|
|
<div id="dialogBody" class="dialog-body"></div>
|
|
<div id="dialogActions" class="dialog-actions"></div>
|
|
</div>
|
|
</section>
|
|
|
|
<div id="statusToast" class="status-toast" role="status" aria-live="polite"></div>
|
|
|
|
<script src="{{ url_for('static', filename='js/00-config.js', v=asset_version) }}" defer></script>
|
|
<script src="{{ url_for('static', filename='js/01-api.js', v=asset_version) }}" defer></script>
|
|
<script src="{{ url_for('static', filename='js/02-chat.js', v=asset_version) }}" defer></script>
|
|
<script src="{{ url_for('static', filename='js/03-admin.js', v=asset_version) }}" defer></script>
|
|
<script src="{{ url_for('static', filename='js/05-feed.js', v=asset_version) }}" defer></script>
|
|
<script src="{{ url_for('static', filename='js/06-pages.js', v=asset_version) }}" defer></script>
|
|
<script src="{{ url_for('static', filename='js/08-settings.js', v=asset_version) }}" defer></script>
|
|
<script src="{{ url_for('static', filename='js/09-profile.js', v=asset_version) }}" defer></script>
|
|
<script src="{{ url_for('static', filename='js/10-reactions.js', v=asset_version) }}" defer></script>
|
|
<script src="{{ url_for('static', filename='js/11-media.js', v=asset_version) }}" defer></script>
|
|
<script src="{{ url_for('static', filename='js/12-calls.js', v=asset_version) }}" defer></script>
|
|
<script src="{{ url_for('static', filename='js/04-main.js', v=asset_version) }}" defer></script>
|
|
<script src="{{ url_for('static', filename='js/07-team-channel-adapter.js', v=asset_version) }}" defer></script>
|
|
</body>
|
|
</html> |