forked from snxraven/peardock
Save connection settings as cookies, add a reset connection button to sidebar
This commit is contained in:
parent
7728e5e5b7
commit
730f356e14
143
app.js
143
app.js
@ -48,33 +48,87 @@ function waitForPeerResponse(expectedMessageFragment, timeout = 900000) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Utility functions for managing cookies
|
||||||
|
function setCookie(name, value, days = 365) {
|
||||||
|
const date = new Date();
|
||||||
|
date.setTime(date.getTime() + days * 24 * 60 * 60 * 1000);
|
||||||
|
const expires = `expires=${date.toUTCString()}`;
|
||||||
|
document.cookie = `${name}=${encodeURIComponent(value)};${expires};path=/`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCookie(name) {
|
||||||
|
const cookies = document.cookie.split('; ');
|
||||||
|
for (let i = 0; i < cookies.length; i++) {
|
||||||
|
const [key, value] = cookies[i].split('=');
|
||||||
|
if (key === name) return decodeURIComponent(value);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function deleteCookie(name) {
|
||||||
|
document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load connections from cookies
|
||||||
|
function loadConnections() {
|
||||||
|
const savedConnections = getCookie('connections');
|
||||||
|
return savedConnections ? JSON.parse(savedConnections) : {};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save connections to cookies
|
||||||
|
function saveConnections() {
|
||||||
|
setCookie('connections', JSON.stringify(connections));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add Reset Connections Button
|
||||||
|
// Toggle Reset Connections Button Visibility
|
||||||
|
function toggleResetButtonVisibility() {
|
||||||
|
const resetConnectionsBtn = document.querySelector('#sidebar .btn-danger');
|
||||||
|
if (!resetConnectionsBtn) return;
|
||||||
|
|
||||||
|
// Show or hide the button based on active connections
|
||||||
|
resetConnectionsBtn.style.display = Object.keys(connections).length > 0 ? 'block' : 'none';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add Reset Connections Button
|
||||||
|
const resetConnectionsBtn = document.createElement('button');
|
||||||
|
resetConnectionsBtn.textContent = 'Reset Connections';
|
||||||
|
resetConnectionsBtn.className = 'btn btn-danger w-100 mt-2';
|
||||||
|
resetConnectionsBtn.addEventListener('click', () => {
|
||||||
|
console.log('[INFO] Resetting connections and clearing cookies.');
|
||||||
|
Object.keys(connections).forEach((topicId) => {
|
||||||
|
disconnectConnection(topicId);
|
||||||
|
});
|
||||||
|
deleteCookie('connections');
|
||||||
|
resetConnectionsView();
|
||||||
|
showWelcomePage();
|
||||||
|
toggleResetButtonVisibility(); // Ensure button visibility is updated
|
||||||
|
});
|
||||||
|
document.getElementById('sidebar').appendChild(resetConnectionsBtn);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Initialize the app
|
// Initialize the app
|
||||||
console.log('[INFO] Client app initialized');
|
console.log('[INFO] Client app initialized');
|
||||||
|
// Load connections from cookies and restore them
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
console.log('[INFO] Initializing Client App');
|
const savedConnections = loadConnections();
|
||||||
|
console.log('[INFO] Restoring saved connections:', savedConnections);
|
||||||
|
|
||||||
const connectionTitle = document.getElementById('connection-title');
|
// Restore saved connections
|
||||||
if (!connectionTitle) {
|
Object.keys(savedConnections).forEach((topicId) => {
|
||||||
console.error('[ERROR] Connection title element is missing! Creating dynamically...');
|
const topicHex = savedConnections[topicId].topicHex;
|
||||||
const content = document.getElementById('content');
|
addConnection(topicHex); // Add connections using the saved topicHex
|
||||||
const titleElement = document.createElement('h1');
|
|
||||||
titleElement.id = 'connection-title';
|
|
||||||
titleElement.textContent = '';
|
|
||||||
titleElement.classList.add('hidden'); // Initially hidden
|
|
||||||
content.insertBefore(titleElement, content.firstChild);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Object.keys(connections).length === 0) {
|
|
||||||
showWelcomePage();
|
|
||||||
} else {
|
|
||||||
hideWelcomePage();
|
|
||||||
}
|
|
||||||
|
|
||||||
assertVisibility(); // Ensure visibility is correct after initialization
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (Object.keys(connections).length > 0) {
|
||||||
|
hideWelcomePage();
|
||||||
|
} else {
|
||||||
|
showWelcomePage();
|
||||||
|
}
|
||||||
|
|
||||||
|
assertVisibility(); // Ensure visibility reflects the restored connections
|
||||||
|
});
|
||||||
|
|
||||||
// Show Status Indicator
|
// Show Status Indicator
|
||||||
// Modify showStatusIndicator to recreate it dynamically
|
// Modify showStatusIndicator to recreate it dynamically
|
||||||
@ -137,6 +191,10 @@ collapseSidebarBtn.addEventListener('click', () => {
|
|||||||
sidebar.classList.toggle('collapsed');
|
sidebar.classList.toggle('collapsed');
|
||||||
const btn = collapseSidebarBtn;
|
const btn = collapseSidebarBtn;
|
||||||
btn.innerHTML = sidebar.classList.contains('collapsed') ? '>' : '<';
|
btn.innerHTML = sidebar.classList.contains('collapsed') ? '>' : '<';
|
||||||
|
|
||||||
|
// Toggle Reset Connections Button Visibility
|
||||||
|
const resetConnectionsBtn = document.querySelector('#sidebar .btn-danger');
|
||||||
|
resetConnectionsBtn.style.display = sidebar.classList.contains('collapsed') ? 'none' : 'block';
|
||||||
});
|
});
|
||||||
|
|
||||||
function handlePeerData(data, topicId, peer) {
|
function handlePeerData(data, topicId, peer) {
|
||||||
@ -188,20 +246,18 @@ addConnectionForm.addEventListener('submit', (e) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Function to add a new connection
|
|
||||||
function addConnection(topicHex) {
|
function addConnection(topicHex) {
|
||||||
console.log(`[DEBUG] Adding connection with topic: ${topicHex}`);
|
console.log(`[DEBUG] Adding connection with topic: ${topicHex}`);
|
||||||
|
|
||||||
if (Object.keys(connections).length === 0) {
|
if (Object.keys(connections).length === 0) {
|
||||||
console.log('[DEBUG] Hiding welcome page after first connection');
|
hideWelcomePage();
|
||||||
hideWelcomePage(); // Hide the welcome page when the first connection is added
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const topic = b4a.from(topicHex, 'hex');
|
const topic = b4a.from(topicHex, 'hex');
|
||||||
const topicId = topicHex.substring(0, 12);
|
const topicId = topicHex.substring(0, 12);
|
||||||
|
|
||||||
console.log(`[INFO] Adding connection with topic: ${topicHex}`);
|
connections[topicId] = { topic, peer: null, swarm: null, topicHex };
|
||||||
assertVisibility(); // Ensure visibility reflects the added connection
|
saveConnections(); // Save updated connections to cookies
|
||||||
|
|
||||||
const connectionItem = document.createElement('li');
|
const connectionItem = document.createElement('li');
|
||||||
connectionItem.className = 'list-group-item d-flex align-items-center justify-content-between';
|
connectionItem.className = 'list-group-item d-flex align-items-center justify-content-between';
|
||||||
@ -215,23 +271,14 @@ function addConnection(topicHex) {
|
|||||||
</button>
|
</button>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
// Add click event to switch connection
|
|
||||||
connectionItem.querySelector('span').addEventListener('click', () => switchConnection(topicId));
|
connectionItem.querySelector('span').addEventListener('click', () => switchConnection(topicId));
|
||||||
|
connectionItem.querySelector('.disconnect-btn').addEventListener('click', (e) => {
|
||||||
// Add click event to the disconnect button
|
e.stopPropagation();
|
||||||
const disconnectBtn = connectionItem.querySelector('.disconnect-btn');
|
|
||||||
disconnectBtn.addEventListener('click', (e) => {
|
|
||||||
e.stopPropagation(); // Prevent triggering the switch connection event
|
|
||||||
disconnectConnection(topicId, connectionItem);
|
disconnectConnection(topicId, connectionItem);
|
||||||
});
|
});
|
||||||
|
|
||||||
connectionList.appendChild(connectionItem);
|
connectionList.appendChild(connectionItem);
|
||||||
|
|
||||||
connections[topicId] = { topic, peer: null, swarm: null };
|
|
||||||
|
|
||||||
console.log('[DEBUG] Updated connections object:', connections);
|
|
||||||
|
|
||||||
// Create a new swarm for this connection
|
|
||||||
const swarm = new Hyperswarm();
|
const swarm = new Hyperswarm();
|
||||||
connections[topicId].swarm = swarm;
|
connections[topicId].swarm = swarm;
|
||||||
|
|
||||||
@ -239,27 +286,18 @@ function addConnection(topicHex) {
|
|||||||
|
|
||||||
swarm.on('connection', (peer) => {
|
swarm.on('connection', (peer) => {
|
||||||
console.log(`[INFO] Connected to peer for topic: ${topicHex}`);
|
console.log(`[INFO] Connected to peer for topic: ${topicHex}`);
|
||||||
|
|
||||||
if (connections[topicId].peer) {
|
if (connections[topicId].peer) {
|
||||||
console.warn(`[WARN] Duplicate connection detected for topic: ${topicId}. Closing.`);
|
|
||||||
peer.destroy();
|
peer.destroy();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
connections[topicId].peer = peer;
|
connections[topicId].peer = peer;
|
||||||
updateConnectionStatus(topicId, true);
|
updateConnectionStatus(topicId, true);
|
||||||
|
|
||||||
peer.on('data', (data) => {
|
peer.on('data', (data) => handlePeerData(data, topicId, peer));
|
||||||
handlePeerData(data, topicId, peer);
|
|
||||||
});
|
|
||||||
|
|
||||||
peer.on('close', () => {
|
peer.on('close', () => {
|
||||||
console.log(`[INFO] Disconnected from peer for topic: ${topicHex}`);
|
|
||||||
updateConnectionStatus(topicId, false);
|
updateConnectionStatus(topicId, false);
|
||||||
|
|
||||||
if (window.activePeer === peer) {
|
if (window.activePeer === peer) {
|
||||||
window.activePeer = null;
|
window.activePeer = null;
|
||||||
// connectionTitle.textContent = 'Disconnected';
|
|
||||||
dashboard.classList.add('hidden');
|
dashboard.classList.add('hidden');
|
||||||
containerList.innerHTML = '';
|
containerList.innerHTML = '';
|
||||||
}
|
}
|
||||||
@ -270,17 +308,28 @@ function addConnection(topicHex) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Automatically collapse the sidebar when a new connection is added
|
// Collapse the sidebar after adding a connection
|
||||||
const sidebar = document.getElementById('sidebar');
|
const sidebar = document.getElementById('sidebar');
|
||||||
const collapseSidebarBtn = document.getElementById('collapse-sidebar-btn');
|
const collapseSidebarBtn = document.getElementById('collapse-sidebar-btn');
|
||||||
if (!sidebar.classList.contains('collapsed')) {
|
if (!sidebar.classList.contains('collapsed')) {
|
||||||
sidebar.classList.add('collapsed');
|
sidebar.classList.add('collapsed');
|
||||||
collapseSidebarBtn.innerHTML = '>';
|
collapseSidebarBtn.innerHTML = '>';
|
||||||
console.log('[DEBUG] Sidebar auto-collapsed after adding a new connection');
|
console.log('[DEBUG] Sidebar collapsed after adding connection');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Initialize connections from cookies on page load
|
||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
const savedConnections = loadConnections();
|
||||||
|
console.log('[INFO] Loading saved connections:', savedConnections);
|
||||||
|
|
||||||
|
Object.keys(savedConnections).forEach((topicId) => {
|
||||||
|
const topicHex = savedConnections[topicId].topic;
|
||||||
|
addConnection(topicHex);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
function disconnectConnection(topicId, connectionItem) {
|
function disconnectConnection(topicId, connectionItem) {
|
||||||
const connection = connections[topicId];
|
const connection = connections[topicId];
|
||||||
|
141
index.html
141
index.html
@ -22,6 +22,7 @@
|
|||||||
color: white;
|
color: white;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hidden {
|
.hidden {
|
||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
@ -79,11 +80,15 @@
|
|||||||
|
|
||||||
#content {
|
#content {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column; /* Keep vertical stacking for child elements */
|
flex-direction: column;
|
||||||
margin-left: 250px; /* Leave space for the sidebar */
|
/* Keep vertical stacking for child elements */
|
||||||
flex: 1; /* Allow the content to grow */
|
margin-left: 250px;
|
||||||
|
/* Leave space for the sidebar */
|
||||||
|
flex: 1;
|
||||||
|
/* Allow the content to grow */
|
||||||
padding: 30px;
|
padding: 30px;
|
||||||
overflow-y: auto; /* Allow scrolling if content overflows */
|
overflow-y: auto;
|
||||||
|
/* Allow scrolling if content overflows */
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -171,7 +176,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
#status-indicator {
|
#status-indicator {
|
||||||
display: none; /* Ensure it's hidden by default */
|
display: none;
|
||||||
|
/* Ensure it's hidden by default */
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
@ -196,36 +202,125 @@
|
|||||||
|
|
||||||
#welcome-page {
|
#welcome-page {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column; /* Stack child elements vertically */
|
flex-direction: column;
|
||||||
justify-content: center; /* Center content vertically */
|
/* Stack child elements vertically */
|
||||||
align-items: center; /* Center content horizontally */
|
justify-content: center;
|
||||||
text-align: center; /* Center-align text */
|
/* Center content vertically */
|
||||||
position: absolute; /* Overlay it over the content area */
|
align-items: center;
|
||||||
|
/* Center content horizontally */
|
||||||
|
text-align: center;
|
||||||
|
/* Center-align text */
|
||||||
|
position: absolute;
|
||||||
|
/* Overlay it over the content area */
|
||||||
top: 50%;
|
top: 50%;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
transform: translate(-50%, -50%); /* Center it perfectly in the content */
|
transform: translate(-50%, -50%);
|
||||||
max-width: 800px; /* Restrict the width of the welcome page */
|
/* Center it perfectly in the content */
|
||||||
width: 100%; /* Allow it to scale */
|
max-width: 800px;
|
||||||
|
/* Restrict the width of the welcome page */
|
||||||
|
width: 100%;
|
||||||
|
/* Allow it to scale */
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
background-color: transparent; /* Match the theme */
|
background-color: transparent;
|
||||||
|
/* Match the theme */
|
||||||
}
|
}
|
||||||
|
|
||||||
#welcome-page.hidden {
|
#welcome-page.hidden {
|
||||||
display: none !important; /* Completely hide when not needed */
|
display: none !important;
|
||||||
|
/* Completely hide when not needed */
|
||||||
}
|
}
|
||||||
|
|
||||||
#dashboard {
|
#dashboard {
|
||||||
display: flex; /* Use flex layout for content within the dashboard */
|
display: flex;
|
||||||
flex-direction: column; /* Stack elements vertically */
|
/* Use flex layout for content within the dashboard */
|
||||||
flex: 1; /* Ensure it uses all available space */
|
flex-direction: column;
|
||||||
width: 100%; /* Take up the full width of the content area */
|
/* Stack elements vertically */
|
||||||
padding: 0; /* Remove extra padding */
|
flex: 1;
|
||||||
overflow-y: auto; /* Allow vertical scrolling if needed */
|
/* Ensure it uses all available space */
|
||||||
position: relative; /* Prevent overlap with other elements */
|
width: 100%;
|
||||||
|
/* Take up the full width of the content area */
|
||||||
|
padding: 0;
|
||||||
|
/* Remove extra padding */
|
||||||
|
overflow-y: auto;
|
||||||
|
/* Allow vertical scrolling if needed */
|
||||||
|
position: relative;
|
||||||
|
/* Prevent overlap with other elements */
|
||||||
}
|
}
|
||||||
|
|
||||||
#dashboard.hidden {
|
#dashboard.hidden {
|
||||||
display: none !important; /* Hide the dashboard completely when not needed */
|
display: none !important;
|
||||||
|
/* Hide the dashboard completely when not needed */
|
||||||
|
}
|
||||||
|
#alert-container {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 20px;
|
||||||
|
right: 20px;
|
||||||
|
z-index: 1055; /* Ensure it overlays important elements only */
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column-reverse; /* Stack alerts upwards */
|
||||||
|
gap: 10px; /* Add space between alerts */
|
||||||
|
pointer-events: none; /* Prevent container from blocking clicks */
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
max-width: 80%;
|
||||||
|
padding: 12px 20px;
|
||||||
|
background-color: #2b2b2b;
|
||||||
|
color: #e0e0e0;
|
||||||
|
border-radius: 6px;
|
||||||
|
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.5);
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
font-size: 14px;
|
||||||
|
animation: fadeIn 0.3s ease-out, fadeOut 4.5s ease-in forwards;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
pointer-events: auto; /* Allow alerts to be interactive */
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert.success {
|
||||||
|
border-left: 6px solid #28a745; /* Green border for success */
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert.danger {
|
||||||
|
border-left: 6px solid #dc3545; /* Red border for danger */
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert .close-btn {
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
color: #e0e0e0;
|
||||||
|
font-size: 16px;
|
||||||
|
cursor: pointer;
|
||||||
|
margin-left: auto; /* Align to the far right */
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
#alert-container {
|
||||||
|
bottom: 10px;
|
||||||
|
right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert {
|
||||||
|
max-width: 90%;
|
||||||
|
font-size: 12px;
|
||||||
|
padding: 10px 15px;
|
||||||
|
white-space: normal; /* Allow wrapping on small screens */
|
||||||
|
text-overflow: clip; /* Disable ellipsis when wrapping */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 768px) {
|
||||||
|
.alert {
|
||||||
|
white-space: nowrap; /* Re-enable nowrap for larger screens */
|
||||||
|
text-overflow: ellipsis; /* Add ellipsis for overflowed text */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#sidebar.collapsed .btn-danger {
|
||||||
|
display: none;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user