Files

525 lines
25 KiB
HTML
Executable File

<!doctype html>
<html lang="en">
<head>
<title id="appTitle">Call-me</title>
<!-- Meta Information -->
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta
name="viewport"
content="width=device-width, height=device-height, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"
/>
<!-- https://favicon.io/favicon-generator/ -->
<link rel="apple-touch-icon" sizes="180x180" href="/favicon/apple-touch-icon.png" />
<link rel="icon" type="image/png" sizes="32x32" href="/favicon/favicon-32x32.png" />
<link rel="icon" type="image/png" sizes="16x16" href="/favicon/favicon-16x16.png" />
<link rel="manifest" href="/favicon/site.webmanifest" />
<!-- https://ogp.me -->
<meta property="og:type" content="app-webrtc" />
<meta property="og:site_name" content="Call-me" />
<meta property="og:title" content="Click the link to make a call." />
<meta property="og:description" content="Your Go-To for Instant Video Calls!" />
<meta property="og:image" content="https://cme.mirotalk.com/assets/callme.png" />
<meta property="og:url" content="https://cme.mirotalk.com" />
<!-- Link to Bootstrap CSS -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap/dist/css/bootstrap.min.css" />
<!-- Link to Font Awesome CSS for icons -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/all.min.css" />
<!-- Link to your custom CSS file -->
<link rel="stylesheet" href="./style.css" />
<!-- Link to SweetAlert CSS file -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/sweetalert2@11.4.8/dist/sweetalert2.min.css" />
<!-- ink to Animate CSS file -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/animate.css/animate.min.css" />
<!-- Link to Toastify CSS file -->
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/toastify-js/src/toastify.min.css" />
</head>
<body>
<!-- The attribution text will be injected here -->
<p id="attribution"></p>
<!-- Optional Random BG Images -->
<img id="randomImage" src="background.jpg" alt="Random Background Image" />
<!-- GitHub project -->
<div id="githubDiv">
<a
class="github-button"
href="https://github.com/miroslavpejic85/call-me"
data-color-scheme="no-preference: light; light: light; dark: dark;"
data-size="large"
data-show-count="true"
aria-label="Star miroslavpejic85/call-me on GitHub"
>Star
</a>
</div>
<!-- Sign-in Page -->
<div id="signInPage" class="container mt-5">
<div class="row justify-content-center">
<div class="col-md-6 col-lg-5 col-xl-4">
<div class="card">
<div class="card-header">
<h1 id="appName" data-i18n="appName">Call-me</h1>
<p class="sign-in-subtitle" data-i18n="signIn.subtitle">
Instant Video Calls. No signup needed.
</p>
</div>
<div class="card-body">
<!-- Sign-in Form -->
<div class="mb-3">
<!-- Input field for entering the username -->
<div class="username-input-wrapper">
<input
id="usernameIn"
type="text"
placeholder="Choose a display name"
data-i18n-placeholder="signIn.username"
required
/>
<button
id="randomUsernameBtn"
class="random-username-btn"
type="button"
title="Generate random username"
>
<i class="fas fa-random"></i>
</button>
<button
id="copyUsernameBtn"
class="copy-username-btn"
type="button"
title="Copy username"
>
<i class="fas fa-copy"></i>
</button>
</div>
</div>
<!-- Media toggles -->
<div class="media-toggles mb-3">
<label class="media-toggle-item" for="joinAudioToggle">
<div class="media-toggle-icon">
<i class="fas fa-microphone"></i>
</div>
<span class="media-toggle-label" data-i18n="signIn.microphone">Microphone</span>
<div class="switch">
<input id="joinAudioToggle" type="checkbox" checked />
<span class="slider"></span>
</div>
</label>
<label class="media-toggle-item" for="joinVideoToggle">
<div class="media-toggle-icon">
<i class="fas fa-video"></i>
</div>
<span class="media-toggle-label" data-i18n="signIn.camera">Camera</span>
<div class="switch">
<input id="joinVideoToggle" type="checkbox" checked />
<span class="slider"></span>
</div>
</label>
</div>
<!-- Sign-in button -->
<button id="signInBtn" class="btn btn-primary" data-i18n="signIn.button">Join</button>
<!-- Direct call section -->
<div class="direct-call-section">
<div class="direct-call-divider">
<span data-i18n="signIn.directCallLabel">Or call someone directly</span>
</div>
<div class="direct-call-row">
<input
id="directCallInput"
type="text"
placeholder="Enter name to call"
data-i18n-placeholder="signIn.directCallPlaceholder"
autocomplete="off"
/>
<button id="directCallBtn" class="btn btn-call-now">
<i class="fas fa-phone"></i>
<span data-i18n="signIn.directCallButton">Call Now</span>
</button>
</div>
</div>
<div class="privacy-divider">
<span><a href="/privacy" class="privacy-link">Privacy Policy</a></span>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Room Page -->
<div id="roomPage" class="container">
<!-- Session time -->
<span id="sessionTime">0s</span>
<!-- Calling overlay (outgoing) -->
<div id="callingOverlay" class="calling-overlay">
<div class="calling-overlay-content">
<div class="calling-pulse-ring"></div>
<i class="fas fa-phone calling-icon"></i>
<p class="calling-status" data-i18n="room.callingOverlay">Calling...</p>
<p id="callingUsername" class="calling-username"></p>
<span id="callingTimer" class="calling-timer">0s</span>
<button id="cancelCallBtn" class="btn btn-danger btn-cancel-call" data-i18n="room.cancelCall">
Cancel
</button>
</div>
</div>
<!-- Incoming call overlay -->
<div id="incomingCallOverlay" class="incoming-call-overlay">
<div class="incoming-call-content">
<div class="incoming-call-ring-outer"></div>
<div class="incoming-call-ring-inner"></div>
<div class="incoming-call-avatar">
<i class="fas fa-user"></i>
</div>
<p class="incoming-call-label" data-i18n="room.incomingCall">Incoming call</p>
<p id="incomingCallUsername" class="incoming-call-username"></p>
<div id="incomingCallTimer" class="incoming-call-timer"></div>
<div class="incoming-call-actions">
<button id="declineCallBtn" class="btn-call-action btn-decline" title="Decline">
<i class="fas fa-phone-slash"></i>
</button>
<button id="acceptCallBtn" class="btn-call-action btn-accept" title="Accept">
<i class="fas fa-phone"></i>
</button>
</div>
</div>
</div>
<!-- Remote video container (video from the other user) -->
<div id="remoteVideoContainer">
<!-- Local video container (your video) -->
<div id="localVideoContainer">
<video id="localVideo"></video>
<span id="localUsername"></span>
</div>
<div id="streamStatusContainer">
<i id="remoteAudioDisabled" class="fas fa-microphone color-red hide"></i>
<i id="remoteVideoDisabled" class="fas fa-video color-red hide"></i>
</div>
<video id="remoteVideo"></video>
<span id="remoteUsername" class="hide"></span>
</div>
<div class="row justify-content-center">
<!-- Button share Room -->
<button
id="shareRoomBtn"
class="btn btn-custom btn-primary btn-m"
data-toggle="tooltip"
data-placement="top"
title="Share room"
data-i18n-title="controls.shareRoom"
>
<i class="fas fa-share-nodes"></i>
</button>
<!-- Button to toggle audio stream -->
<button
id="audioBtn"
class="btn btn-custom btn-success btn-m"
data-toggle="tooltip"
data-placement="top"
title="Toggle audio"
data-i18n-title="controls.toggleAudio"
>
<i class="fas fa-microphone"></i>
</button>
<!-- Button to toggle video stream -->
<button
id="videoBtn"
class="btn btn-custom btn-success btn-m"
data-toggle="tooltip"
data-placement="top"
title="Toggle video"
data-i18n-title="controls.toggleVideo"
>
<i class="fas fa-video"></i>
</button>
<!-- Button to swap camera -->
<button
id="swapCameraBtn"
class="btn btn-custom btn-success btn-m"
data-toggle="tooltip"
data-placement="top"
title="Swap camera"
data-i18n-title="controls.swapCamera"
>
<i class="fas fa-camera-rotate"></i>
</button>
<!-- Button to share screen -->
<button
id="screenShareBtn"
class="btn btn-custom btn-success btn-m"
data-toggle="tooltip"
data-placement="top"
title="Toggle screen"
data-i18n-title="controls.toggleScreen"
>
<i class="fas fa-desktop"></i>
</button>
<!-- Toggle user sidebar button -->
<button
id="sidebarBtn"
class="btn btn-custom btn-primary btn-m"
data-toggle="tooltip"
data-placement="top"
title="Toggle users"
data-i18n-title="controls.toggleUsers"
>
<i class="fas fa-users"></i>
<span id="participantCount" class="participant-count hidden">0</span>
<span id="messageCount" class="message-count hidden">0</span>
</button>
<!-- Button to leave the call -->
<button
id="leaveBtn"
class="btn btn-custom btn-danger btn-m"
data-toggle="tooltip"
data-placement="top"
title="Leave"
data-i18n-title="controls.leave"
>
<i class="fas fa-phone-slash red"></i>
</button>
</div>
</div>
<!-- Sidebar with tabs for users and chat -->
<div id="userSidebar" class="user-sidebar">
<div class="user-sidebar-header">
<div class="sidebar-tabs">
<button
id="usersTab"
class="sidebar-tab active"
data-tab="users"
title="Users"
data-i18n-title="room.users"
data-toggle="tooltip"
data-placement="bottom"
>
<i class="fas fa-users"></i> <span data-i18n="room.users">Users</span>
</button>
<button
id="chatTab"
class="sidebar-tab"
data-tab="chat"
title="Chat"
data-i18n-title="room.chat"
data-toggle="tooltip"
data-placement="bottom"
>
<i class="fas fa-comments"></i> <span data-i18n="room.chat">Chat</span>
<span id="chatNotification" class="chat-notification hidden">0</span>
</button>
<button
id="settingsTab"
class="sidebar-tab"
data-tab="settings"
title="Settings"
data-i18n-title="settings.settings"
data-toggle="tooltip"
data-placement="bottom"
>
<i class="fas fa-cog"></i> <span data-i18n="settings.settings">Settings</span>
</button>
</div>
<button
id="exitSidebarBtn"
class="btn btn-exit-sidebar"
title="Close sidebar"
data-i18n-title="room.closeSidebar"
>
<i class="fas fa-times"></i>
</button>
</div>
<!-- Users Tab Content -->
<div id="usersContent" class="tab-content active">
<div class="user-search-bar">
<div class="user-search-wrapper">
<i class="fas fa-search"></i>
<input
type="text"
id="userSearchInput"
placeholder="Search users..."
data-i18n-placeholder="room.searchUsers"
autocomplete="off"
/>
</div>
</div>
<ul id="userList" class="user-list"></ul>
</div>
<!-- Chat Tab Content -->
<div id="chatContent" class="tab-content">
<div id="chatMessages" class="chat-messages"></div>
<form id="chatForm" class="chat-form" autocomplete="off">
<button
type="button"
id="emojiBtn"
class="btn btn-emoji"
title="Add emoji"
data-i18n-title="chat.addEmoji"
>
<i class="fas fa-smile"></i>
</button>
<input
id="chatInput"
type="text"
placeholder="Type a message..."
data-i18n-placeholder="chat.typeMessage"
autocomplete="off"
/>
<button type="submit" class="btn btn-primary btn-send-chat" data-i18n-title="chat.sendMessage">
<i class="fas fa-paper-plane"></i>
</button>
</form>
<div id="emojiPicker" class="emoji-picker-container"></div>
</div>
<!-- Settings Tab Content -->
<div id="settingsContent" class="tab-content">
<div class="settings-section">
<h3 class="settings-title">
<i class="fas fa-globe"></i> <span data-i18n="settings.language">Language</span>
</h3>
<div class="setting-group">
<label for="languageSelect" class="setting-label">
<i class="fas fa-language"></i>
<span data-i18n="settings.selectLanguage">Select Language</span>
</label>
<select id="languageSelect" class="setting-select"></select>
</div>
<h3 class="settings-title">
<i class="fas fa-sliders-h"></i>
<span data-i18n="settings.generalTitle">General</span>
</h3>
<div class="setting-group setting-toggle-group">
<label for="hideLocalVideoToggle" class="setting-label">
<i class="fas fa-eye-slash"></i>
<span data-i18n="settings.hideLocalVideo">Hide Local Video</span>
</label>
<label class="toggle-switch">
<input type="checkbox" id="hideLocalVideoToggle" />
<span class="toggle-slider"></span>
</label>
</div>
<div id="pushNotificationGroup" class="setting-group setting-toggle-group">
<label for="pushNotificationToggle" class="setting-label">
<i class="fas fa-bell"></i>
<span data-i18n="settings.pushNotifications">Push Notifications</span>
</label>
<div class="push-toggle-wrapper">
<label class="toggle-switch">
<input type="checkbox" id="pushNotificationToggle" />
<span class="toggle-slider"></span>
</label>
<button id="pushTestBtn" class="btn-setting" data-i18n="settings.testPush">Test</button>
</div>
</div>
<h3 class="settings-title">
<i class="fas fa-video"></i> <span data-i18n="settings.mediaDevicesTitle">Media Devices</span>
</h3>
<div class="setting-group">
<label for="videoSelect" class="setting-label">
<i class="fas fa-camera"></i> <span data-i18n="settings.videoInput">Camera</span>
</label>
<select id="videoSelect" class="setting-select">
<option value="" data-i18n="settings.loadingCameras">Loading cameras...</option>
</select>
</div>
<div class="setting-group">
<label for="audioSelect" class="setting-label">
<i class="fas fa-microphone"></i> <span data-i18n="settings.audioInput">Microphone</span>
</label>
<select id="audioSelect" class="setting-select">
<option value="" data-i18n="settings.loadingMicrophones">Loading microphones...</option>
</select>
</div>
<div class="setting-group">
<label for="audioOutputSelect" class="setting-label">
<i class="fas fa-volume-up"></i> <span data-i18n="settings.audioOutput">Speaker</span>
</label>
<select id="audioOutputSelect" class="setting-select">
<option value="" data-i18n="settings.loadingSpeakers">Loading speakers...</option>
</select>
</div>
<div class="settings-actions">
<button id="testDevicesBtn" class="btn btn-success btn-test-devices">
<i class="fas fa-play"></i> <span data-i18n="settings.testDevices">Test Devices</span>
</button>
<button id="refreshDevicesBtn" class="btn btn-secondary btn-refresh-devices">
<i class="fas fa-sync"></i> <span data-i18n="settings.refresh">Refresh</span>
</button>
</div>
<h3 class="settings-title">
<i class="fas fa-comments"></i>
<span data-i18n="settings.chatSettingsTitle">Chat Settings</span>
</h3>
<div class="settings-actions">
<button id="saveChatBtn" class="btn btn-success btn-save-chat">
<i class="fas fa-download"></i> <span data-i18n="settings.saveMessages">Save Messages</span>
</button>
<button id="clearChatBtn" class="btn btn-danger btn-clear-chat">
<i class="fas fa-trash"></i> <span data-i18n="settings.clearAll">Clear All</span>
</button>
</div>
</div>
</div>
</div>
<!-- JavaScript libraries for WebSocket and custom client code -->
<script src="/socket.io/socket.io.js"></script>
<script src="config.js"></script>
<script src="i18n.js"></script>
<script src="client.js"></script>
<!-- Include UaParser -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/UAParser.js/1.0.37/ua-parser.min.js"></script>
<!-- Include Axios file -->
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<!-- Include SweetAlert JS file -->
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11.4.8/dist/sweetalert2.all.min.js"></script>
<!-- Include GitHub buttons -->
<script src="https://buttons.github.io/buttons.js"></script>
<!-- Include Emoji Mart for emoji picker -->
<script defer src="https://cdn.jsdelivr.net/npm/emoji-mart@latest/dist/browser.js"></script>
<!-- Include Toastify JS file -->
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/toastify-js"></script>
<!-- Bootstrap JS -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>