mirror of
https://github.com/PR0M3TH3AN/TORCH.git
synced 2026-10-27 07:51:52 +00:00
feat: add required acknowledgement warning to install copy button
- Adds a modal to `landing/index.html` warning users about the "freshly vibecoded" nature of the project. - Intercepts the "Install via NPM" copy button to require acknowledgement before copying. - Styles the modal with a danger theme consistent with the warning. - Verified with Playwright. Co-authored-by: PR0M3TH3AN <[email protected]>
This commit is contained in:
1 parent
14002a7bf9
commit
ac7ba2a895
7 files changed
+221
-2
No files matched your search
+124
-2
@@ -439,6 +439,75 @@
|
||||
.copy-install-btn:active {
|
||||
transform: scale(0.98);
|
||||
}
|
||||
|
||||
/* Acknowledgement Modal Styles */
|
||||
#ackModal .modal-content {
|
||||
border-color: var(--danger);
|
||||
max-width: 500px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#ackModal h2 {
|
||||
color: var(--danger);
|
||||
margin-top: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
#ackModal .modal-body {
|
||||
font-size: 1.1rem;
|
||||
color: var(--text);
|
||||
margin: 1.5rem 0;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
#ackModal .modal-actions {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 1rem;
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
#ackModal .btn-cancel {
|
||||
background: transparent;
|
||||
border: 1px solid var(--border);
|
||||
color: var(--text);
|
||||
padding: 0.75rem 1.5rem;
|
||||
border-radius: 9999px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
#ackModal .btn-cancel:hover {
|
||||
background: var(--surface-alt);
|
||||
color: var(--text-strong);
|
||||
}
|
||||
|
||||
#ackModal .btn-confirm {
|
||||
background: var(--danger);
|
||||
border: 1px solid var(--danger);
|
||||
color: white;
|
||||
padding: 0.75rem 1.5rem;
|
||||
border-radius: 9999px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
font-weight: 600;
|
||||
box-shadow: 0 4px 12px rgba(255, 50, 50, 0.3);
|
||||
}
|
||||
|
||||
#ackModal .btn-confirm:hover {
|
||||
background: #ff4d4d; /* lighter red */
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 6px 16px rgba(255, 50, 50, 0.4);
|
||||
}
|
||||
|
||||
/* Define danger color if not exists in dashboard/styles.css */
|
||||
:root {
|
||||
--danger: #ef4444;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
@@ -469,7 +538,7 @@
|
||||
<p class="install-label">Install via NPM</p>
|
||||
<div class="install-code-wrapper">
|
||||
<code id="install-cmd">npm install torch-lock</code>
|
||||
<button class="copy-install-btn" onclick="copyToClipboard('install-cmd', this)">
|
||||
<button class="copy-install-btn" onclick="copyToClipboard('install-cmd', this, true)">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect>
|
||||
<path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>
|
||||
@@ -539,6 +608,27 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Acknowledgement Modal -->
|
||||
<div id="ackModal" class="modal">
|
||||
<div class="modal-content">
|
||||
<h2>
|
||||
<svg width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"></path>
|
||||
<line x1="12" y1="9" x2="12" y2="13"></line>
|
||||
<line x1="12" y1="17" x2="12.01" y2="17"></line>
|
||||
</svg>
|
||||
Warning: Vibecoded Project
|
||||
</h2>
|
||||
<div class="modal-body">
|
||||
This is a freshly vibecoded project and that using this in a valuable production repo is reckless.
|
||||
</div>
|
||||
<div class="modal-actions">
|
||||
<button class="btn-cancel" onclick="dismissAckModal()">Cancel</button>
|
||||
<button class="btn-confirm" onclick="confirmAck()">I Understand, Copy</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// Modal Logic
|
||||
const modal = document.getElementById("docsModal");
|
||||
@@ -562,6 +652,9 @@
|
||||
if (event.target == modal) {
|
||||
modal.classList.remove("show");
|
||||
}
|
||||
if (event.target == ackModal) {
|
||||
dismissAckModal();
|
||||
}
|
||||
}
|
||||
|
||||
// Fetch and Render Markdown
|
||||
@@ -609,7 +702,36 @@
|
||||
}
|
||||
}
|
||||
|
||||
function copyToClipboard(elementId, btn) {
|
||||
// Acknowledgement Logic
|
||||
let hasAcknowledged = false;
|
||||
let pendingCopy = null;
|
||||
const ackModal = document.getElementById('ackModal');
|
||||
|
||||
function showAckModal(callback) {
|
||||
pendingCopy = callback;
|
||||
ackModal.classList.add('show');
|
||||
}
|
||||
|
||||
function dismissAckModal() {
|
||||
ackModal.classList.remove('show');
|
||||
pendingCopy = null;
|
||||
}
|
||||
|
||||
function confirmAck() {
|
||||
hasAcknowledged = true;
|
||||
ackModal.classList.remove('show');
|
||||
if (pendingCopy) {
|
||||
pendingCopy();
|
||||
pendingCopy = null;
|
||||
}
|
||||
}
|
||||
|
||||
function copyToClipboard(elementId, btn, requiresAck = false) {
|
||||
if (requiresAck && !hasAcknowledged) {
|
||||
showAckModal(() => copyToClipboard(elementId, btn, false));
|
||||
return;
|
||||
}
|
||||
|
||||
const code = document.getElementById(elementId).textContent;
|
||||
navigator.clipboard.writeText(code).then(() => {
|
||||
const originalContent = btn.innerHTML;
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 79 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 81 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 82 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 74 KiB |
@@ -0,0 +1,63 @@
|
||||
from playwright.sync_api import sync_playwright, expect
|
||||
|
||||
def test_ack_modal():
|
||||
with sync_playwright() as p:
|
||||
browser = p.chromium.launch(headless=True)
|
||||
# Grant clipboard permissions
|
||||
context = browser.new_context(permissions=["clipboard-read", "clipboard-write"])
|
||||
page = context.new_page()
|
||||
|
||||
page.on("console", lambda msg: print(f"Console: {msg.text}"))
|
||||
|
||||
try:
|
||||
page.goto("http://localhost:8000/landing/index.html")
|
||||
|
||||
copy_btn = page.locator(".copy-install-btn")
|
||||
ack_modal = page.locator("#ackModal")
|
||||
|
||||
# 1. Click Copy
|
||||
print("Clicking Copy...")
|
||||
copy_btn.click()
|
||||
|
||||
# 2. Verify Modal Appears
|
||||
expect(ack_modal).to_be_visible()
|
||||
print("Modal appeared.")
|
||||
|
||||
# Verify text is NOT copied yet (button text hasn't changed)
|
||||
expect(copy_btn).not_to_have_text("Copied!", timeout=500)
|
||||
print("Copy deferred.")
|
||||
|
||||
page.screenshot(path="verification/modal_visible.png")
|
||||
|
||||
# 3. Click Cancel
|
||||
cancel_btn = page.locator("#ackModal .btn-cancel")
|
||||
cancel_btn.click()
|
||||
|
||||
expect(ack_modal).not_to_be_visible()
|
||||
expect(copy_btn).not_to_have_text("Copied!")
|
||||
print("Cancelled correctly.")
|
||||
|
||||
# 4. Click Copy Again
|
||||
copy_btn.click()
|
||||
expect(ack_modal).to_be_visible()
|
||||
|
||||
# 5. Click Confirm
|
||||
confirm_btn = page.locator("#ackModal .btn-confirm")
|
||||
confirm_btn.click()
|
||||
|
||||
expect(ack_modal).not_to_be_visible()
|
||||
expect(copy_btn).to_have_text("Copied!", timeout=2000)
|
||||
print("Confirmed and copied.")
|
||||
|
||||
page.screenshot(path="verification/after_ack.png")
|
||||
print("Verification successful.")
|
||||
|
||||
except Exception as e:
|
||||
print(f"Verification failed: {e}")
|
||||
page.screenshot(path="verification/failure.png")
|
||||
raise e
|
||||
finally:
|
||||
browser.close()
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_ack_modal()
|
||||
@@ -0,0 +1,34 @@
|
||||
from playwright.sync_api import sync_playwright, expect
|
||||
|
||||
def test_copy_button():
|
||||
with sync_playwright() as p:
|
||||
browser = p.chromium.launch(headless=True)
|
||||
# Grant clipboard permissions
|
||||
context = browser.new_context(permissions=["clipboard-read", "clipboard-write"])
|
||||
page = context.new_page()
|
||||
|
||||
page.on("console", lambda msg: print(f"Console: {msg.text}"))
|
||||
|
||||
try:
|
||||
page.goto("http://localhost:8000/landing/index.html")
|
||||
|
||||
copy_btn = page.locator(".copy-install-btn")
|
||||
expect(copy_btn).to_be_visible()
|
||||
|
||||
copy_btn.click()
|
||||
|
||||
# Verify text changes to "Copied!"
|
||||
expect(copy_btn).to_have_text("Copied!", timeout=2000)
|
||||
|
||||
page.screenshot(path="verification/before_change.png")
|
||||
print("Successfully verified copy button works without warning.")
|
||||
|
||||
except Exception as e:
|
||||
print(f"Verification failed: {e}")
|
||||
page.screenshot(path="verification/failure.png")
|
||||
raise e
|
||||
finally:
|
||||
browser.close()
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_copy_button()
|
||||
Reference in new issue
Block a user