Compare commits

...

26 Commits
main ... main

Author SHA1 Message Date
Raven Scott
7c874fab21 Auto Join Guild on Create 2024-07-08 00:57:58 -04:00
Raven Scott
f125cad87c change screenshot 2024-07-08 00:41:46 -04:00
Raven Scott
cb88b16606 Readd Markdown Support + Syntax Highlights and DOMPurify is used to sanitize HTML content to prevent XSS attacks. 2024-07-07 23:42:17 -04:00
94ea9b6840 Merge pull request 'Feat: Adding GUILDS!' (#12) from guilds into main
Reviewed-on: snxraven/LinkUp-P2P-Chat#12
2024-07-07 23:01:33 -04:00
Raven Scott
7eddd45f79 Only auto play on peers 2024-07-07 22:49:15 -04:00
Raven Scott
70bc69ddea auto play audio messages 2024-07-07 22:45:55 -04:00
Raven Scott
aa70e42fdc change internal agent prefix 2024-07-07 22:40:22 -04:00
Raven Scott
c530a8d69c Add back file menu 2024-07-07 22:39:31 -04:00
Raven Scott
084cb02a11 fix icon message 2024-07-07 22:00:13 -04:00
Raven Scott
a0c7eb1561 fix 2024-07-07 21:52:57 -04:00
Raven Scott
43e9890235 readd updateIcon 2024-07-07 21:49:13 -04:00
Raven Scott
ed4625275d init all guild topics on start 2024-07-07 21:40:52 -04:00
Raven Scott
55875f468c more test 2024-07-07 21:30:09 -04:00
Raven Scott
e0ad9c7067 more test 2024-07-07 21:21:55 -04:00
Raven Scott
d423031cfb more test 2024-07-07 21:14:17 -04:00
Raven Scott
181d011b8d more test 2024-07-07 21:08:30 -04:00
Raven Scott
6cfbb36d35 Merge branch 'guilds' of git.ssh.surf:snxraven/LinkUp-P1P-Chat into guilds 2024-07-07 20:51:41 -04:00
Raven Scott
da1bf28e3d test 2024-07-07 20:51:12 -04:00
Raven Scott
a1b11f7ae6 test 2024-07-07 20:46:59 -04:00
de9e01e932 revert 8c0f7ebd0f
revert test
2024-06-22 21:19:28 +00:00
Raven Scott
8c0f7ebd0f test 2024-06-22 16:56:04 -04:00
Raven Scott
0e6d074c11 test 2024-06-22 16:53:07 -04:00
Raven Scott
6ea37b8082 test 2024-06-22 16:52:05 -04:00
Raven Scott
fd02cff23f test 2024-06-22 16:49:42 -04:00
Raven Scott
cd92618351 Add the beginnings of guilds 2024-06-20 00:46:24 -04:00
9d759e5af3 Merge pull request 'fix: make avatars not draggable and selectable' (#11) from Cyber/LinkUp-P2P-Chat:main into main
Reviewed-on: snxraven/LinkUp-P2P-Chat#11

Good Job!
2024-06-15 17:50:47 +00:00
7 changed files with 1106 additions and 494 deletions

1187
app.js

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
export default { export default {
handler: function(bot, args, message) { handler: function(bot, args, message) {
// Specify the path to the file you want to send // Specify the path to the file you want to send
const filePath = '/to/file/path.js'; // Replace with the actual file path const filePath = '/Users/raven/chat/chatBot/bot.js'; // Replace with the actual file path
const fileType = 'text/html'; // Specify the correct file type const fileType = 'text/html'; // Specify the correct file type
// Send the file message using the bot instance // Send the file message using the bot instance

View File

@ -1,4 +1,3 @@
// commands.js
import b4a from 'b4a'; import b4a from 'b4a';
import fs from 'fs'; import fs from 'fs';
@ -12,45 +11,94 @@ if (fs.existsSync(agentAvatarPath)) {
} }
export default async function handleCommand(command, context) { export default async function handleCommand(command, context) {
const { eventEmitter, currentTopic, clearMessages, addMessage, joinRoom, leaveRoom, createRoom, listFiles } = context; const { eventEmitter, currentTopic, clearMessages, addMessage, joinRoom, leaveRoom, createRoom, listFiles, deleteFile, servePort } = context;
console.log("Context received in handleCommand:", context); // Add logging
const args = command.trim().split(' '); const args = command.trim().split(' ');
const cmd = args[0].toLowerCase(); const cmd = args[0].toLowerCase();
const restArgs = args.slice(1).join(' '); const restArgs = args.slice(1).join(' ');
console.log("Command received:", cmd); // Add logging
console.log("Current topic:", currentTopic); // Add logging to check the current topic
switch (cmd) { switch (cmd) {
case '~clear': case '>clear':
clearMessages(); clearMessages(currentTopic);
break; break;
case '~ping': case '>ping':
addMessage('LinkUp', 'pong', agentAvatar, currentTopic()); addMessage('LinkUp', 'pong', agentAvatar, currentTopic);
break; break;
case '~help': case '>help':
addMessage('LinkUp', 'Available commands:\n- ~clear\n- ~ping\n- ~help\n- ~join [topic]\n- ~leave\n- ~create [alias]\n- ~list-files', agentAvatar, currentTopic()); addMessage('LinkUp', 'Available commands:\n- >clear\n- >ping\n- >help\n- >join [topic]\n- >leave\n- >create [alias]\n- >list-files', agentAvatar, currentTopic);
break; break;
case '~join': case '>join':
if (restArgs) { if (restArgs) {
await joinRoom(restArgs); await joinRoom(currentTopic, restArgs);
} else { } else {
addMessage('LinkUp', 'Usage: ~join [topic]', agentAvatar, currentTopic()); addMessage('LinkUp', 'Usage: >join [topic]', agentAvatar, currentTopic);
} }
break; break;
case '~leave': case '>leave':
leaveRoom(currentTopic()); leaveRoom(currentTopic);
break; break;
case '~create': case '>create':
if (restArgs) { if (restArgs) {
await createRoom(restArgs); await createRoom(currentTopic, restArgs);
} else { } else {
addMessage('LinkUp', 'Usage: ~create [alias]', agentAvatar, currentTopic()); addMessage('LinkUp', 'Usage: >create [alias]', agentAvatar, currentTopic);
} }
break; break;
case '~list-files': case '>list-files':
const files = await listFiles(); const files = await listFiles();
const fileList = files.length > 0 ? files.map(file => `- ${file}`).join('\n') : 'No files available'; const fileList = files.length > 0 ? files.map(file => `- ${file}`).join('\n') : 'No files available';
addMessage('LinkUp', `Available files:\n${fileList}`, agentAvatar, currentTopic()); addMessage('LinkUp', `Available files:\n${fileList}`, agentAvatar, currentTopic);
// Render the file list with delete buttons
renderFileList(files, deleteFile, servePort);
break; break;
default: default:
addMessage('LinkUp', `Unknown command: ${cmd}`, agentAvatar, currentTopic);
console.log('Unknown command:', command); console.log('Unknown command:', command);
} }
} }
function renderFileList(files, deleteFile, servePort) {
const container = document.querySelector('#messages');
if (!container) {
console.error('Element #messages not found');
return;
}
const fileList = document.createElement('ul');
files.forEach(file => {
const listItem = document.createElement('li');
const fileButton = document.createElement('button');
fileButton.textContent = file.trim();
fileButton.onclick = () => downloadFile(file.trim(), servePort);
const deleteButton = document.createElement('button');
deleteButton.textContent = 'Delete';
deleteButton.onclick = async () => {
await deleteFile(file);
listItem.remove();
};
listItem.appendChild(fileButton);
listItem.appendChild(deleteButton);
fileList.appendChild(listItem);
});
container.appendChild(fileList);
}
function downloadFile(filename, servePort) {
const url = `http://localhost:${servePort}/files/${filename}`;
const link = document.createElement('a');
link.href = url;
link.download = filename;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 251 KiB

After

Width:  |  Height:  |  Size: 55 KiB

View File

@ -17,10 +17,10 @@
</header> </header>
<main> <main>
<div id="sidebar"> <div id="sidebar">
<ul id="room-list"> <ul id="guild-list" class="list-group">
<!-- Room list will be populated dynamically --> <!-- Guild list will be populated dynamically -->
</ul> </ul>
<button id="toggle-setup-btn">Create/Join Room</button> <button id="toggle-setup-btn">Create/Join Guild</button>
</div> </div>
<div id="content"> <div id="content">
<div id="register" class="hidden"> <div id="register" class="hidden">
@ -35,12 +35,12 @@
<div id="user-info"> <div id="user-info">
<!-- User info will be populated dynamically --> <!-- User info will be populated dynamically -->
</div> </div>
<button id="create-chat-room">Create Room</button> <button id="create-guild-btn">Create Guild</button>
<div id="or">- or -</div> <div id="or">- or -</div>
<div id="join-chat-room-container"> <div id="join-guild-container">
<label for="connection-topic">Topic:</label> <label for="join-guild-topic">Guild Topic:</label>
<input type="text" id="join-chat-room-topic" placeholder="connection topic"> <input type="text" id="join-guild-topic" placeholder="guild topic">
<button id="join-chat-room">Join Room</button> <button id="join-guild">Join Guild</button>
</div> </div>
</div> </div>
<div id="chat" class="hidden"> <div id="chat" class="hidden">
@ -49,11 +49,10 @@
<div style="display: inline;"> <div style="display: inline;">
<strong><span id="chat-room-name"></span></strong> | <a href="#" id="copy-topic-link" class="mini-button">Copy Topic</a> <strong><span id="chat-room-name"></span></strong> | <a href="#" id="copy-topic-link" class="mini-button">Copy Topic</a>
<span id="chat-room-topic" style="display: none;"></span> <span id="chat-room-topic" style="display: none;"></span>
<span id="chat-guild-topic" style="display: none;"></span>
<span id="chat-guild-name" style="display: none;"></span>
</div> </div>
</div> </div>
<div id="user-list">
<!-- User list will be populated here -->
</div>
</div> </div>
<div id="messages-container"> <div id="messages-container">
<div id="messages"></div> <div id="messages"></div>
@ -62,7 +61,7 @@
<textarea id="message" rows="4"></textarea> <textarea id="message" rows="4"></textarea>
<input type="file" id="file-input" style="display:none;"> <input type="file" id="file-input" style="display:none;">
<button type="button" id="attach-file">Attach File</button> <button type="button" id="attach-file">Attach File</button>
<button type="button" id="talk-btn">Talk</button> <!-- New Talk button --> <button type="button" id="talk-btn">Talk</button>
<input type="submit" value="Send" /> <input type="submit" value="Send" />
</form> </form>
<button id="remove-room-btn">Leave Room</button> <button id="remove-room-btn">Leave Room</button>
@ -70,11 +69,46 @@
<div id="loading" class="hidden">Loading ...</div> <div id="loading" class="hidden">Loading ...</div>
</div> </div>
</main> </main>
<!-- Create Guild Modal -->
<div id="create-guild-modal" class="modal hidden">
<div class="modal-content">
<span class="close-btn" id="close-create-guild-modal">&times;</span>
<h2>Create Guild</h2>
<form id="create-guild-form">
<label for="guild-name">Guild Name:</label>
<input type="text" id="guild-name" required>
<button type="submit">Create</button>
</form>
</div>
</div>
<!-- Manage Guild Modal -->
<div id="manage-guild-modal" class="modal hidden">
<div class="modal-content">
<span class="close-btn" id="close-manage-guild-modal">&times;</span>
<h2>Manage Guild</h2>
<div id="guild-info">
<!-- Guild info will be populated dynamically -->
</div>
<button id="copy-guild-id" class="mini-button">Copy Guild ID</button>
<form id="add-room-form">
<label for="room-name">Room Name:</label>
<input type="text" id="room-name" required>
<button type="submit">Add Room</button>
</form>
<ul id="room-list">
<!-- Room list will be populated dynamically -->
</ul>
</div>
</div>
<script> <script>
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
const messageInput = document.getElementById('message'); const messageInput = document.getElementById('message');
const copyTopicLink = document.getElementById('copy-topic-link'); const copyTopicLink = document.getElementById('copy-topic-link');
const chatRoomTopic = document.getElementById('chat-room-topic'); const chatRoomTopic = document.getElementById('chat-room-topic');
const copyGuildIdButton = document.getElementById('copy-guild-id');
if (messageInput) { if (messageInput) {
messageInput.addEventListener('keydown', function(event) { messageInput.addEventListener('keydown', function(event) {
@ -101,32 +135,123 @@
}); });
} }
const switchRoom = (topic) => { if (copyGuildIdButton) {
console.log('Switching to room:', topic); // Debugging log copyGuildIdButton.addEventListener('click', function(event) {
const chatRoomTopic = document.querySelector('#chat-room-topic'); event.preventDefault();
const chatRoomName = document.querySelector('#chat-room-name'); const guildTopic = document.getElementById('manage-guild-modal').dataset.guildTopic;
navigator.clipboard.writeText(guildTopic).then(() => {
console.log('Guild ID copied to clipboard:', guildTopic);
}).catch(err => {
console.error('Failed to copy guild ID:', err);
});
});
}
if (chatRoomTopic) { const guildList = document.querySelector('#guild-list');
chatRoomTopic.innerText = topic; // Set full topic here if (guildList) {
} else { guildList.addEventListener('click', function(event) {
console.error('Element #chat-room-topic not found'); const roomItem = event.target.closest('.room-item');
}
// Show chat UI elements
document.querySelector('#chat').classList.remove('hidden');
document.querySelector('#setup').classList.add('hidden');
};
const roomList = document.querySelector('#room-list');
if (roomList) {
roomList.addEventListener('click', function(event) {
const roomItem = event.target.closest('li');
if (roomItem) { if (roomItem) {
switchRoom(roomItem.dataset.topic); const guildTopic = roomItem.dataset.guildTopic;
const roomTopic = roomItem.dataset.topic;
switchRoom(guildTopic, roomTopic);
} }
}); });
} }
const createGuildBtn = document.getElementById('create-guild-btn');
const createGuildModal = document.getElementById('create-guild-modal');
const closeCreateGuildModal = document.getElementById('close-create-guild-modal');
const createGuildForm = document.getElementById('create-guild-form');
createGuildBtn.addEventListener('click', () => {
createGuildModal.classList.remove('hidden');
});
closeCreateGuildModal.addEventListener('click', () => {
createGuildModal.classList.add('hidden');
});
createGuildForm.addEventListener('submit', (event) => {
event.preventDefault();
const guildName = document.getElementById('guild-name').value.trim();
if (guildName) {
createGuild(guildName);
createGuildModal.classList.add('hidden');
}
});
const joinGuildBtn = document.getElementById('join-guild');
joinGuildBtn.addEventListener('click', async (event) => {
const guildTopic = document.getElementById('join-guild-topic').value.trim();
if (guildTopic) {
await joinGuildRequest(guildTopic);
}
});
const manageGuildModal = document.getElementById('manage-guild-modal');
const closeManageGuildModal = document.getElementById('close-manage-guild-modal');
const addRoomForm = document.getElementById('add-room-form');
const roomNameInput = document.getElementById('room-name');
closeManageGuildModal.addEventListener('click', () => {
manageGuildModal.classList.add('hidden');
});
addRoomForm.addEventListener('submit', (event) => {
event.preventDefault();
const roomName = roomNameInput.value.trim();
const guildTopic = manageGuildModal.dataset.guildTopic;
if (roomName && guildTopic) {
addRoomToGuild(guildTopic, roomName);
roomNameInput.value = '';
}
});
}); });
function createGuild(guildName) {
const event = new CustomEvent('createGuild', { detail: { guildName } });
document.dispatchEvent(event);
}
function addRoomToGuild(guildTopic, roomName) {
const event = new CustomEvent('addRoomToGuild', { detail: { guildTopic, roomName } });
document.dispatchEvent(event);
}
function manageGuild(guildTopic) {
const event = new CustomEvent('manageGuild', { detail: { guildTopic } });
document.dispatchEvent(event);
}
function switchRoom(guildTopic, roomTopic) {
const event = new CustomEvent('switchRoom', { detail: { guildTopic, roomTopic } });
document.dispatchEvent(event);
}
function openManageGuildModal(guildTopic) {
const manageGuildModal = document.getElementById('manage-guild-modal');
const guildInfo = document.getElementById('guild-info');
const roomList = document.getElementById('room-list');
manageGuildModal.dataset.guildTopic = guildTopic;
guildInfo.innerHTML = `<h3>${config.guilds[guildTopic].alias}</h3>`;
roomList.innerHTML = '';
config.guilds[guildTopic].rooms.forEach(room => {
const roomItem = document.createElement('li');
roomItem.textContent = room.alias;
roomItem.dataset.guildTopic = guildTopic;
roomItem.dataset.topic = room.topic;
roomItem.addEventListener('dblclick', () => enterEditMode(roomItem, guildTopic));
roomItem.addEventListener('click', () => switchRoom(guildTopic, room.topic));
roomList.appendChild(roomItem);
});
manageGuildModal.classList.remove('hidden');
}
</script> </script>
</body> </body>
</html> </html>

View File

@ -24,12 +24,15 @@
"dependencies": { "dependencies": {
"b4a": "^1.6.6", "b4a": "^1.6.6",
"corestore": "^6.18.2", "corestore": "^6.18.2",
"dompurify": "^3.1.6",
"dotenv": "^16.4.5", "dotenv": "^16.4.5",
"electron": "^30.0.8", "electron": "^30.0.8",
"highlight.js": "^11.10.0",
"hypercore-crypto": "^3.4.1", "hypercore-crypto": "^3.4.1",
"hyperdrive": "^11.8.1", "hyperdrive": "^11.8.1",
"hyperswarm": "^4.7.14", "hyperswarm": "^4.7.14",
"localdrive": "^1.11.4", "localdrive": "^1.11.4",
"markdown-it": "^14.1.0",
"marked": "^12.0.2", "marked": "^12.0.2",
"serve-drive": "^5.0.8" "serve-drive": "^5.0.8"
} }

133
style.css
View File

@ -281,7 +281,6 @@ textarea::placeholder {
background-color: #f04747; background-color: #f04747;
} }
/* Main container styles */ /* Main container styles */
main { main {
display: flex; display: flex;
@ -474,78 +473,146 @@ main {
} }
/* Updated Room List Styles */ /* Updated Room List Styles */
#room-list { #guild-list {
list-style: none; list-style: none;
padding: 0; padding: 0;
margin: 0; margin: 0;
} }
#room-list li { .guild-item {
padding: 10px; padding: 10px;
margin-bottom: 10px; margin-bottom: 10px;
background-color: #3a3f44; background-color: #3a3f44;
border-radius: 5px; border-radius: 5px;
cursor: pointer; cursor: pointer;
display: flex; display: flex;
flex-direction: column;
transition: background-color 0.3s ease;
}
.guild-item:hover {
background-color: #4a5258;
}
.guild-item h3 {
margin: 0;
font-size: 16px;
color: #ffffff;
}
.guild-item .manage-guild-btn {
align-self: flex-end;
margin-top: 10px;
font-size: 12px;
padding: 5px 10px;
}
.guild-item .room-list {
list-style: none;
padding: 0;
margin: 10px 0 0 0;
display: flex;
flex-direction: column;
}
.guild-item .room-list li {
padding: 5px;
margin-bottom: 5px;
background-color: #464343;
border-radius: 3px;
cursor: pointer;
display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
transition: background-color 0.3s ease; transition: background-color 0.3s ease;
} }
#room-list li:hover { .guild-item .room-list li:hover {
background-color: #4a5258; background-color: #5a5f64;
} }
#room-list li span { .guild-item .room-list li span {
flex: 1; flex: 1;
} }
#room-list li .edit-icon, .guild-item .room-list li .edit-icon,
#room-list li .delete-icon { .guild-item .room-list li .delete-icon {
margin-left: 10px; margin-left: 10px;
color: #e0e0e0; color: #e0e0e0;
cursor: pointer; cursor: pointer;
transition: color 0.3s ease; transition: color 0.3s ease;
} }
#room-list li .edit-icon:hover, .guild-item .room-list li .edit-icon:hover,
#room-list li .delete-icon:hover { .guild-item .room-list li .delete-icon:hover {
color: #a0a0a0; color: #a0a0a0;
} }
/* Style for Edit Mode Input Box */ /* Modal styles */
#room-list li input[type="text"] { .modal {
display: flex;
justify-content: center;
align-items: center;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.8);
z-index: 1000;
}
.modal-content {
background-color: #2e2e2e; background-color: #2e2e2e;
border: 1px solid #464343; padding: 1.5rem;
border-radius: 5px; border-radius: 8px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.5);
max-width: 500px;
width: 100%;
text-align: center;
}
.close-btn {
color: #e0e0e0; color: #e0e0e0;
padding: 5px; float: right;
width: calc(100% - 40px); font-size: 1.5rem;
margin-right: 10px; cursor: pointer;
transition: background-color 0.3s ease, color 0.3s ease, border-color 0.3s ease;
} }
#room-list li input[type="text"]:focus { .close-btn:hover {
outline: none; color: #f04747;
background-color: #3a3a3a;
} }
/* Link styles */ .modal h2 {
a { margin-bottom: 1rem;
color: #e0e0e0; /* Base color for links matching the text color */ color: #fff;
text-decoration: none; /* Remove underline */
transition: color 0.3s ease, text-decoration 0.3s ease;
} }
a:hover { .modal form {
color: #b0b0b0; /* Lighter color on hover */ display: flex;
text-decoration: underline; /* Underline on hover */ flex-direction: column;
align-items: center;
} }
a:active { .modal form input,
color: #a0a0a0; /* Slightly darker color on active */ .modal form button {
margin-bottom: 1rem;
width: 100%;
} }
a:visited { .modal form button {
color: #b0b0b0; /* Different color for visited links */ width: auto;
background-color: #3e3e3e;
color: #fff;
border: none;
padding: 0.75rem 1.5rem;
border-radius: 5px;
cursor: pointer;
transition: background-color 0.3s ease, transform 0.3s ease;
} }
.modal form button:hover {
background-color: #191919;
transform: scale(1.05);
}