Move code for tutorial to its own file
This commit is contained in:
@ -272,5 +272,4 @@
|
|||||||
|
|
||||||
.bg-gray-800.p-6.rounded-lg.shadow-lg p {
|
.bg-gray-800.p-6.rounded-lg.shadow-lg p {
|
||||||
@apply max-w-full;
|
@apply max-w-full;
|
||||||
}
|
}
|
||||||
|
|
@ -447,114 +447,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
|
||||||
// Debounce function to prevent multiple triggers on mobile
|
|
||||||
function debounce(func, wait) {
|
|
||||||
let timeout;
|
|
||||||
return function executedFunction(...args) {
|
|
||||||
const later = () => {
|
|
||||||
clearTimeout(timeout);
|
|
||||||
func(...args);
|
|
||||||
};
|
|
||||||
clearTimeout(timeout);
|
|
||||||
timeout = setTimeout(later, wait);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Function to update tutorial spans when key display spans are populated
|
|
||||||
function updateTutorialSpans() {
|
|
||||||
const holesailHash = document.getElementById('holesailHash').textContent;
|
|
||||||
const geyserHash = document.getElementById('geyserHash').textContent;
|
|
||||||
const sftpHash = document.getElementById('sftpHash').textContent;
|
|
||||||
|
|
||||||
document.getElementById('tutorialHolesailHash').textContent = holesailHash;
|
|
||||||
document.getElementById('tutorialGeyserHash').textContent = geyserHash;
|
|
||||||
document.getElementById('tutorialSftpHash').textContent = sftpHash;
|
|
||||||
document.getElementById('tutorialHolesailHashOutput').textContent = holesailHash;
|
|
||||||
document.getElementById('tutorialHolesailHashOutput2').textContent = holesailHash;
|
|
||||||
document.getElementById('tutorialHolesailHashHost').textContent = holesailHash;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run initially
|
|
||||||
updateTutorialSpans();
|
|
||||||
|
|
||||||
// Observe changes to key display spans
|
|
||||||
const observer = new MutationObserver(updateTutorialSpans);
|
|
||||||
document.querySelectorAll('#holesailHash, #geyserHash, #sftpHash').forEach(span => {
|
|
||||||
observer.observe(span, { childList: true, characterData: true, subtree: true });
|
|
||||||
});
|
|
||||||
|
|
||||||
// Ensure notification is hidden on page load
|
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
|
||||||
const notification = document.getElementById('copyNotification');
|
|
||||||
notification.classList.add('hidden');
|
|
||||||
|
|
||||||
// Add event listeners to copy buttons
|
|
||||||
document.querySelectorAll('.copy-key-btn').forEach(button => {
|
|
||||||
button.addEventListener('click', debounce((event) => {
|
|
||||||
event.preventDefault(); // Prevent default touch behavior
|
|
||||||
if (!event.isTrusted) return; // Ensure user-initiated action
|
|
||||||
|
|
||||||
const keyElementId = button.getAttribute('data-key-id');
|
|
||||||
const keyText = document.getElementById(keyElementId).textContent;
|
|
||||||
const keyType = button.getAttribute('data-key-type');
|
|
||||||
|
|
||||||
if (navigator.clipboard && navigator.clipboard.writeText) {
|
|
||||||
navigator.clipboard.writeText(keyText).then(() => {
|
|
||||||
// Use showNotification from app.js
|
|
||||||
window.showNotification(`${keyType} key copied to clipboard!`, 'success', `copy-${keyElementId}`);
|
|
||||||
}).catch(err => {
|
|
||||||
console.error(`Failed to copy ${keyType} key: `, err);
|
|
||||||
window.showNotification(`Failed to copy ${keyType} key.`, 'error', `copy-${keyElementId}`);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
window.showNotification('Clipboard API not supported. Please copy manually.', 'error', `copy-${keyElementId}`);
|
|
||||||
}
|
|
||||||
}, 300));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// Toggle tutorial section visibility
|
|
||||||
document.getElementById('toggleTutorial').addEventListener('click', () => {
|
|
||||||
const tutorialSection = document.getElementById('tutorialSection');
|
|
||||||
tutorialSection.classList.toggle('hidden');
|
|
||||||
});
|
|
||||||
|
|
||||||
// Copy summarized tutorial in Markdown with debounced event listener
|
|
||||||
document.getElementById('copyTutorial').addEventListener('click', debounce((event) => {
|
|
||||||
event.preventDefault(); // Prevent default touch behavior
|
|
||||||
if (!event.isTrusted) return; // Ensure user-initiated action
|
|
||||||
|
|
||||||
const holesailHash = document.getElementById('holesailHash').textContent;
|
|
||||||
const markdownTutorial = `# Join My Minecraft Server with Holesail!
|
|
||||||
|
|
||||||
Holesail is a secure, peer-to-peer tool that lets you connect to my server without public IPs.
|
|
||||||
|
|
||||||
1. **Install Node.js**: Download and install from [nodejs.org](https://nodejs.org/).
|
|
||||||
2. **Install Holesail**: Open a terminal and run:
|
|
||||||
\`\`\`bash
|
|
||||||
npm i holesail@2.1.0
|
|
||||||
\`\`\`
|
|
||||||
3. **Connect to the server**: Use this command with the key:
|
|
||||||
\`\`\`bash
|
|
||||||
holesail ${holesailHash}
|
|
||||||
\`\`\`
|
|
||||||
4. **Join in Minecraft**: Once Holesail confirms the connection, connect to \`127.0.0.1:25565\` in Minecraft.
|
|
||||||
|
|
||||||
**Note**: Keep the key private, like an SSH key. No public IPs needed—it's all peer-to-peer!`;
|
|
||||||
|
|
||||||
if (navigator.clipboard && navigator.clipboard.writeText) {
|
|
||||||
navigator.clipboard.writeText(markdownTutorial).then(() => {
|
|
||||||
window.showNotification('Tutorial copied to clipboard!', 'success', 'copy-tutorial');
|
|
||||||
}).catch(err => {
|
|
||||||
console.error('Failed to copy tutorial: ', err);
|
|
||||||
window.showNotification('Failed to copy tutorial. Please copy manually.', 'error', 'copy-tutorial');
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
window.showNotification('Clipboard API not supported. Please copy manually.', 'error', 'copy-tutorial');
|
|
||||||
}
|
|
||||||
}, 300)); // 300ms debounce
|
|
||||||
</script>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</main>
|
</main>
|
||||||
@ -572,6 +464,8 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="js/app.js"></script>
|
<script src="js/app.js"></script>
|
||||||
|
<script src="js/tutorial.js"></script>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
105
public/js/tutorial.js
Normal file
105
public/js/tutorial.js
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
// Debounce function to prevent multiple triggers on mobile
|
||||||
|
function debounce(func, wait) {
|
||||||
|
let timeout;
|
||||||
|
return function executedFunction(...args) {
|
||||||
|
const later = () => {
|
||||||
|
clearTimeout(timeout);
|
||||||
|
func(...args);
|
||||||
|
};
|
||||||
|
clearTimeout(timeout);
|
||||||
|
timeout = setTimeout(later, wait);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to update tutorial spans when key display spans are populated
|
||||||
|
function updateTutorialSpans() {
|
||||||
|
const holesailHash = document.getElementById('holesailHash').textContent;
|
||||||
|
const geyserHash = document.getElementById('geyserHash').textContent;
|
||||||
|
const sftpHash = document.getElementById('sftpHash').textContent;
|
||||||
|
|
||||||
|
document.getElementById('tutorialHolesailHash').textContent = holesailHash;
|
||||||
|
document.getElementById('tutorialGeyserHash').textContent = geyserHash;
|
||||||
|
document.getElementById('tutorialSftpHash').textContent = sftpHash;
|
||||||
|
document.getElementById('tutorialHolesailHashOutput').textContent = holesailHash;
|
||||||
|
document.getElementById('tutorialHolesailHashOutput2').textContent = holesailHash;
|
||||||
|
document.getElementById('tutorialHolesailHashHost').textContent = holesailHash;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run initially
|
||||||
|
updateTutorialSpans();
|
||||||
|
|
||||||
|
// Observe changes to key display spans
|
||||||
|
const observer = new MutationObserver(updateTutorialSpans);
|
||||||
|
document.querySelectorAll('#holesailHash, #geyserHash, #sftpHash').forEach(span => {
|
||||||
|
observer.observe(span, { childList: true, characterData: true, subtree: true });
|
||||||
|
});
|
||||||
|
|
||||||
|
// Ensure notification is hidden on page load
|
||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
const notification = document.getElementById('copyNotification');
|
||||||
|
|
||||||
|
// Add event listeners to copy buttons
|
||||||
|
document.querySelectorAll('.copy-key-btn').forEach(button => {
|
||||||
|
button.addEventListener('click', debounce((event) => {
|
||||||
|
event.preventDefault(); // Prevent default touch behavior
|
||||||
|
if (!event.isTrusted) return; // Ensure user-initiated action
|
||||||
|
|
||||||
|
const keyElementId = button.getAttribute('data-key-id');
|
||||||
|
const keyText = document.getElementById(keyElementId).textContent;
|
||||||
|
const keyType = button.getAttribute('data-key-type');
|
||||||
|
|
||||||
|
if (navigator.clipboard && navigator.clipboard.writeText) {
|
||||||
|
navigator.clipboard.writeText(keyText).then(() => {
|
||||||
|
// Use showNotification from app.js
|
||||||
|
window.showNotification(`${keyType} key copied to clipboard!`, 'success', `copy-${keyElementId}`);
|
||||||
|
}).catch(err => {
|
||||||
|
console.error(`Failed to copy ${keyType} key: `, err);
|
||||||
|
window.showNotification(`Failed to copy ${keyType} key.`, 'error', `copy-${keyElementId}`);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
window.showNotification('Clipboard API not supported. Please copy manually.', 'error', `copy-${keyElementId}`);
|
||||||
|
}
|
||||||
|
}, 300));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Toggle tutorial section visibility
|
||||||
|
document.getElementById('toggleTutorial').addEventListener('click', () => {
|
||||||
|
const tutorialSection = document.getElementById('tutorialSection');
|
||||||
|
tutorialSection.classList.toggle('hidden');
|
||||||
|
});
|
||||||
|
|
||||||
|
// Copy summarized tutorial in Markdown with debounced event listener
|
||||||
|
document.getElementById('copyTutorial').addEventListener('click', debounce((event) => {
|
||||||
|
event.preventDefault(); // Prevent default touch behavior
|
||||||
|
if (!event.isTrusted) return; // Ensure user-initiated action
|
||||||
|
|
||||||
|
const holesailHash = document.getElementById('holesailHash').textContent;
|
||||||
|
const markdownTutorial = `# Join My Minecraft Server with Holesail!
|
||||||
|
|
||||||
|
Holesail is a secure, peer-to-peer tool that lets you connect to my server without public IPs.
|
||||||
|
|
||||||
|
1. **Install Node.js**: Download and install from [nodejs.org](https://nodejs.org/).
|
||||||
|
2. **Install Holesail**: Open a terminal and run:
|
||||||
|
\`\`\`bash
|
||||||
|
npm i holesail@2.1.0
|
||||||
|
\`\`\`
|
||||||
|
3. **Connect to the server**: Use this command with the key:
|
||||||
|
\`\`\`bash
|
||||||
|
holesail ${holesailHash}
|
||||||
|
\`\`\`
|
||||||
|
4. **Join in Minecraft**: Once Holesail confirms the connection, connect to \`127.0.0.1:25565\` in Minecraft.
|
||||||
|
|
||||||
|
**Note**: Keep the key private, like an SSH key. No public IPs needed—it's all peer-to-peer!`;
|
||||||
|
|
||||||
|
if (navigator.clipboard && navigator.clipboard.writeText) {
|
||||||
|
navigator.clipboard.writeText(markdownTutorial).then(() => {
|
||||||
|
window.showNotification('Tutorial copied to clipboard!', 'success', 'copy-tutorial');
|
||||||
|
}).catch(err => {
|
||||||
|
console.error('Failed to copy tutorial: ', err);
|
||||||
|
window.showNotification('Failed to copy tutorial. Please copy manually.', 'error', 'copy-tutorial');
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
window.showNotification('Clipboard API not supported. Please copy manually.', 'error', 'copy-tutorial');
|
||||||
|
}
|
||||||
|
}, 300)); // 300ms debounce
|
Reference in New Issue
Block a user