Claude Project Delete Button

Add a delete button to Claude projects

Dovrai installare un'estensione come Tampermonkey, Greasemonkey o Violentmonkey per installare questo script.

You will need to install an extension such as Tampermonkey to install this script.

Dovrai installare un'estensione come Tampermonkey o Violentmonkey per installare questo script.

Dovrai installare un'estensione come Tampermonkey o Userscripts per installare questo script.

Dovrai installare un'estensione come ad esempio Tampermonkey per installare questo script.

Dovrai installare un gestore di script utente per installare questo script.

(Ho già un gestore di script utente, lasciamelo installare!)

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

(Ho già un gestore di stile utente, lasciamelo installare!)

// ==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
// ==/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 = `
            <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" fill="currentColor" viewBox="0 0 256 256" class="-translate-y-[0.5px]">
                <path d="M216,48H176V40a24,24,0,0,0-24-24H104A24,24,0,0,0,80,40v8H40a8,8,0,0,0,0,16h8V208a16,16,0,0,0,16,16H192a16,16,0,0,0,16-16V64h8a8,8,0,0,0,0-16ZM96,40a8,8,0,0,1,8-8h48a8,8,0,0,1,8,8v8H96Zm96,168H64V64H192ZM112,104v64a8,8,0,0,1-16,0V104a8,8,0,0,1,16,0Zm48,0v64a8,8,0,0,1-16,0V104a8,8,0,0,1,16,0Z"></path>
            </svg>
        `;

        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();
    }
})();