Claude Project Delete Button

Add a delete button to Claude projects

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey, Greasemonkey alebo Violentmonkey.

Na inštaláciu tohto skriptu je potrebné nainštalovať rozšírenie, ako napríklad Tampermonkey.

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey, % alebo Violentmonkey.

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey alebo Userscripts.

Na inštaláciu tohto skriptu je potrebné nainštalovať rozšírenie, ako napríklad Tampermonkey.

Na inštaláciu tohto skriptu je potrebné nainštalovať rozšírenie správcu používateľských skriptov.

(Už mám správcu používateľských skriptov, nechajte ma ho nainštalovať!)

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

(Už mám správcu používateľských štýlov, nechajte ma ho nainštalovať!)

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