Warning: fopen(/www/sites/update.greasyfork.icu/index/store/temp/b41cf8226ca7fb17bdbd130ee941844b.js): failed to open stream: No space left on device in /www/sites/update.greasyfork.icu/index/scriptControl.php on line 65
// ==UserScript== // @name Claude Project Delete Button // @namespace Violentmonkey Scripts // @match https://claude.ai/project/* // @grant none // @version 1.0 // @author Elias Benbourenane // @description Add a delete button to Claude projects // @license MIT // @downloadURL https://update.greasyfork.icu/scripts/539259/Claude%20Project%20Delete%20Button.user.js // @updateURL https://update.greasyfork.icu/scripts/539259/Claude%20Project%20Delete%20Button.meta.js // ==/UserScript== (function() { 'use strict'; function getProjectId() { const path = window.location.pathname; const match = path.match(/\/project\/([^\/]+)/); return match ? match[1] : null; } function getOrgId() { return window.intercomSettings?.lastActiveOrgUUID; } function createDeleteButton() { const deleteButton = document.createElement('button'); deleteButton.className = `inline-flex items-center justify-center relative shrink-0 can-focus select-none disabled:pointer-events-none disabled:opacity-50 disabled:shadow-none disabled:drop-shadow-none text-text-300 border-transparent transition font-styrene duration-300 ease-[cubic-bezier(0.165,0.85,0.45,1)] hover:bg-bg-400 aria-pressed:bg-bg-400 aria-checked:bg-bg-400 aria-expanded:bg-bg-300 hover:text-text-100 aria-pressed:text-text-100 aria-checked:text-text-100 aria-expanded:text-text-100 h-8 w-8 rounded-md active:scale-95`.replace(/\s+/g, ' '); deleteButton.type = 'button'; deleteButton.title = 'Delete Project'; // Trash icon SVG deleteButton.innerHTML = ` `; deleteButton.addEventListener('click', handleDeleteClick); return deleteButton; } async function handleDeleteClick(event) { event.preventDefault(); const projectId = getProjectId(); const orgId = getOrgId(); if (!projectId || !orgId) { alert('Unable to determine project or organization ID'); return; } if (!confirm('Are you sure you want to delete this project? This action cannot be undone.')) { return; } try { const response = await fetch(`https://claude.ai/api/organizations/${orgId}/projects/${projectId}`, { method: 'DELETE', credentials: 'include', headers: { 'Content-Type': 'application/json', } }); if (response.ok) { alert('Project deleted successfully'); window.location.href = 'https://claude.ai/'; } else { throw new Error(`Delete failed: ${response.status} ${response.statusText}`); } } catch (error) { console.error('Error deleting project:', error); alert('Failed to delete project. Please try again.'); } } function addDeleteButton() { // Look for the container with the star and menu buttons const buttonContainer = document.querySelector('.flex.items-center.gap-1.ml-auto'); if (buttonContainer && !buttonContainer.querySelector('[title="Delete Project"]')) { const deleteButton = createDeleteButton(); // Insert the delete button before the menu button (last button) const menuButton = buttonContainer.lastElementChild; buttonContainer.insertBefore(deleteButton, menuButton); } } let currentUrl = window.location.href; function isProjectPage() { return window.location.pathname.startsWith('/project/'); } function handleUrlChange() { const newUrl = window.location.href; if (newUrl !== currentUrl) { currentUrl = newUrl; if (isProjectPage()) { // Delay to allow page content to load setTimeout(addDeleteButton, 500); setTimeout(addDeleteButton, 1500); setTimeout(addDeleteButton, 3000); } } } // Override history methods to detect programmatic navigation const originalPushState = history.pushState; const originalReplaceState = history.replaceState; history.pushState = function(...args) { originalPushState.apply(history, args); setTimeout(handleUrlChange, 0); }; history.replaceState = function(...args) { originalReplaceState.apply(history, args); setTimeout(handleUrlChange, 0); }; function init() { if (isProjectPage()) { // Try to add the button immediately addDeleteButton(); // Also try after delays in case the page is still loading setTimeout(addDeleteButton, 500); setTimeout(addDeleteButton, 1500); setTimeout(addDeleteButton, 3000); } // Set up a mutation observer to handle dynamic content loading const observer = new MutationObserver(function(mutations) { mutations.forEach(function(mutation) { if (mutation.type === 'childList' && mutation.addedNodes.length > 0) { // Only try to add button if we're on a project page if (isProjectPage()) { addDeleteButton(); } } }); }); observer.observe(document.body, { childList: true, subtree: true }); // Listen for browser back/forward navigation window.addEventListener('popstate', handleUrlChange); // Periodic check to ensure button is present (fallback) setInterval(() => { if (isProjectPage()) { addDeleteButton(); } }, 2000); } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); } })();