Skip to content

Instantly share code, notes, and snippets.

@simonw
Created September 21, 2024 00:07
Show Gist options
  • Save simonw/7d806c0dc63a1d8f0ae1b20608cab98f to your computer and use it in GitHub Desktop.
Save simonw/7d806c0dc63a1d8f0ae1b20608cab98f to your computer and use it in GitHub Desktop.

GitHub API File Upload Example

human (Sep 20, 2024, 04:56 PM)

Write me an example HTML page with HTML and JavaScript that uses the GitHub API to write files to a repository

assistant (Sep 20, 2024, 04:56 PM)

Certainly, I can help you create an HTML page with JavaScript that uses the GitHub API to write files to a repository. However, it's important to note that for security reasons, you typically wouldn't want to include your GitHub token directly in client-side code. In a real-world scenario, you'd want to handle this through a backend service. But for demonstration purposes, I'll create a simple example.

HTML page using GitHub API to write files

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>GitHub API File Writer</title>
</head>
<body>
    <h1>GitHub API File Writer</h1>
    <form id="fileForm">
        <label for="token">GitHub Token:</label>
        <input type="password" id="token" required><br><br>
        
        <label for="owner">Repository Owner:</label>
        <input type="text" id="owner" required><br><br>
        
        <label for="repo">Repository Name:</label>
        <input type="text" id="repo" required><br><br>
        
        <label for="path">File Path:</label>
        <input type="text" id="path" required><br><br>
        
        <label for="content">File Content:</label><br>
        <textarea id="content" rows="10" cols="50" required></textarea><br><br>
        
        <button type="submit">Create File</button>
    </form>

    <div id="result"></div>

    <script>
        document.getElementById('fileForm').addEventListener('submit', function(e) {
            e.preventDefault();
            
            const token = document.getElementById('token').value;
            const owner = document.getElementById('owner').value;
            const repo = document.getElementById('repo').value;
            const path = document.getElementById('path').value;
            const content = document.getElementById('content').value;

            const url = `https://api.github.com/repos/${owner}/${repo}/contents/${path}`;

            fetch(url, {
                method: 'PUT',
                headers: {
                    'Authorization': `token ${token}`,
                    'Content-Type': 'application/json',
                },
                body: JSON.stringify({
                    message: 'Create file via API',
                    content: btoa(content) // Base64 encode the content
                })
            })
            .then(response => response.json())
            .then(data => {
                if (data.content) {
                    document.getElementById('result').innerHTML = `File created successfully. <a href="${data.content.html_url}" target="_blank">View file</a>`;
                } else {
                    document.getElementById('result').innerHTML = `Error: ${JSON.stringify(data)}`;
                }
            })
            .catch(error => {
                document.getElementById('result').innerHTML = `Error: ${error.message}`;
            });
        });
    </script>
</body>
</html>

This HTML page provides a simple form where you can enter:

  1. Your GitHub personal access token
  2. The repository owner's username
  3. The repository name
  4. The file path where you want to create the file
  5. The content of the file

When you submit the form, it uses the GitHub API to create a new file in the specified repository.

A few important notes:

  1. This is a basic example and doesn't include error handling for all possible scenarios.
  2. It uses the btoa() function to Base64 encode the file content, which is required by the GitHub API.
  3. As mentioned earlier, exposing your GitHub token in client-side code is not secure. In a real application, you would want to handle the API requests server-side.
  4. This example creates a new file. If you want to update an existing file, you'd need to first fetch the file's SHA and include it in your PUT request.

Would you like me to explain any part of this code in more detail?

human (Sep 20, 2024, 05:04 PM)

Add an option to specify an image file, which then gets created in GitHub instead of the textarea content -include a button to clear the image

assistant (Sep 20, 2024, 05:04 PM)

Certainly! I'll modify the HTML page to include an option for specifying an image file, which will then be uploaded to GitHub instead of the textarea content. I'll also add a button to clear the selected image.

HTML page using GitHub API to write files or upload images

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>GitHub API File/Image Writer</title>
</head>
<body>
    <h1>GitHub API File/Image Writer</h1>
    <form id="fileForm">
        <label for="token">GitHub Token:</label>
        <input type="password" id="token" required><br><br>
        
        <label for="owner">Repository Owner:</label>
        <input type="text" id="owner" required><br><br>
        
        <label for="repo">Repository Name:</label>
        <input type="text" id="repo" required><br><br>
        
        <label for="path">File Path:</label>
        <input type="text" id="path" required><br><br>
        
        <label for="contentType">Content Type:</label>
        <select id="contentType">
            <option value="text">Text</option>
            <option value="image">Image</option>
        </select><br><br>
        
        <div id="textContent">
            <label for="content">File Content:</label><br>
            <textarea id="content" rows="10" cols="50"></textarea><br><br>
        </div>
        
        <div id="imageContent" style="display:none;">
            <label for="image">Select Image:</label>
            <input type="file" id="image" accept="image/*"><br><br>
            <button type="button" id="clearImage">Clear Image</button><br><br>
        </div>
        
        <button type="submit">Create File/Upload Image</button>
    </form>

    <div id="result"></div>

    <script>
        const contentTypeSelect = document.getElementById('contentType');
        const textContent = document.getElementById('textContent');
        const imageContent = document.getElementById('imageContent');
        const clearImageBtn = document.getElementById('clearImage');
        const imageInput = document.getElementById('image');

        contentTypeSelect.addEventListener('change', function() {
            if (this.value === 'text') {
                textContent.style.display = 'block';
                imageContent.style.display = 'none';
            } else {
                textContent.style.display = 'none';
                imageContent.style.display = 'block';
            }
        });

        clearImageBtn.addEventListener('click', function() {
            imageInput.value = '';
        });

        document.getElementById('fileForm').addEventListener('submit', function(e) {
            e.preventDefault();
            
            const token = document.getElementById('token').value;
            const owner = document.getElementById('owner').value;
            const repo = document.getElementById('repo').value;
            const path = document.getElementById('path').value;
            const contentType = document.getElementById('contentType').value;

            const url = `https://api.github.com/repos/${owner}/${repo}/contents/${path}`;

            let content;
            if (contentType === 'text') {
                content = document.getElementById('content').value;
                uploadToGitHub(url, token, btoa(content));
            } else {
                const file = document.getElementById('image').files[0];
                if (file) {
                    const reader = new FileReader();
                    reader.onload = function(e) {
                        content = e.target.result.split(',')[1]; // Get base64 data
                        uploadToGitHub(url, token, content);
                    };
                    reader.readAsDataURL(file);
                } else {
                    document.getElementById('result').innerHTML = 'Please select an image file.';
                }
            }
        });

        function uploadToGitHub(url, token, content) {
            fetch(url, {
                method: 'PUT',
                headers: {
                    'Authorization': `token ${token}`,
                    'Content-Type': 'application/json',
                },
                body: JSON.stringify({
                    message: 'Create file/image via API',
                    content: content
                })
            })
            .then(response => response.json())
            .then(data => {
                if (data.content) {
                    document.getElementById('result').innerHTML = `File/Image created successfully. <a href="${data.content.html_url}" target="_blank">View file</a>`;
                } else {
                    document.getElementById('result').innerHTML = `Error: ${JSON.stringify(data)}`;
                }
            })
            .catch(error => {
                document.getElementById('result').innerHTML = `Error: ${error.message}`;
            });
        }
    </script>
</body>
</html>

I've updated the HTML page to include the option for uploading an image file to GitHub. Here are the key changes and additions:

  1. Added a dropdown to select between text and image content types.
  2. Created a new section for image upload with a file input and a clear button.
  3. Modified the JavaScript to handle both text and image uploads.
  4. Implemented the clear image functionality.

Here's a breakdown of the new features:

  1. Content Type Selection:

    • Users can now choose between uploading text or an image using the dropdown menu.
    • The appropriate input (textarea for text, file input for image) is displayed based on the selection.
  2. Image Upload:

    • When "Image" is selected, users can choose an image file from their device.
    • The selected image is read as a Base64-encoded string before uploading.
  3. Clear Image Button:

    • This button allows users to clear their image selection if they want to choose a different file.
  4. Handling Both Content Types:

    • The script now checks the content type before processing the upload.
    • For text, it uses the textarea content.
    • For images, it reads the file and extracts the Base64-encoded data.
  5. GitHub API Integration:

    • The upload process remains similar, but now it can handle both text and image content.
    • The Base64-encoded content (whether text or image) is sent to the GitHub API.

This solution provides a more versatile tool for uploading both text files and images to a GitHub repository. However, please note that this is still a client-side implementation, and in a production environment, you would want to handle the GitHub API calls server-side for security reasons.

Would you like me to explain any specific part of this code in more detail?

human (Sep 20, 2024, 05:05 PM)

add a little bit of CSS to make everything look nicer

assistant (Sep 20, 2024, 05:05 PM)

Certainly! I'll add some CSS to improve the appearance of the page. We'll make it more visually appealing and easier to use.

Styled HTML page using GitHub API to write files or upload images

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>GitHub API File/Image Writer</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            line-height: 1.6;
            color: #333;
            max-width: 800px;
            margin: 0 auto;
            padding: 20px;
            background-color: #f4f4f4;
        }
        h1 {
            color: #2c3e50;
            text-align: center;
        }
        form {
            background-color: #fff;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 0 10px rgba(0,0,0,0.1);
        }
        label {
            display: block;
            margin-bottom: 5px;
            font-weight: bold;
        }
        input[type="text"], input[type="password"], select, textarea {
            width: 100%;
            padding: 8px;
            margin-bottom: 10px;
            border: 1px solid #ddd;
            border-radius: 4px;
            box-sizing: border-box;
        }
        button {
            background-color: #3498db;
            color: #fff;
            padding: 10px 15px;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            font-size: 16px;
        }
        button:hover {
            background-color: #2980b9;
        }
        #clearImage {
            background-color: #e74c3c;
        }
        #clearImage:hover {
            background-color: #c0392b;
        }
        #result {
            margin-top: 20px;
            padding: 10px;
            border-radius: 4px;
        }
        #result:not(:empty) {
            background-color: #d4edda;
            border: 1px solid #c3e6cb;
            color: #155724;
        }
    </style>
</head>
<body>
    <h1>GitHub API File/Image Writer</h1>
    <form id="fileForm">
        <label for="token">GitHub Token:</label>
        <input type="password" id="token" required>
        
        <label for="owner">Repository Owner:</label>
        <input type="text" id="owner" required>
        
        <label for="repo">Repository Name:</label>
        <input type="text" id="repo" required>
        
        <label for="path">File Path:</label>
        <input type="text" id="path" required>
        
        <label for="contentType">Content Type:</label>
        <select id="contentType">
            <option value="text">Text</option>
            <option value="image">Image</option>
        </select>
        
        <div id="textContent">
            <label for="content">File Content:</label>
            <textarea id="content" rows="10"></textarea>
        </div>
        
        <div id="imageContent" style="display:none;">
            <label for="image">Select Image:</label>
            <input type="file" id="image" accept="image/*">
            <button type="button" id="clearImage">Clear Image</button>
        </div>
        
        <button type="submit">Create File/Upload Image</button>
    </form>

    <div id="result"></div>

    <script>
        const contentTypeSelect = document.getElementById('contentType');
        const textContent = document.getElementById('textContent');
        const imageContent = document.getElementById('imageContent');
        const clearImageBtn = document.getElementById('clearImage');
        const imageInput = document.getElementById('image');

        contentTypeSelect.addEventListener('change', function() {
            if (this.value === 'text') {
                textContent.style.display = 'block';
                imageContent.style.display = 'none';
            } else {
                textContent.style.display = 'none';
                imageContent.style.display = 'block';
            }
        });

        clearImageBtn.addEventListener('click', function() {
            imageInput.value = '';
        });

        document.getElementById('fileForm').addEventListener('submit', function(e) {
            e.preventDefault();
            
            const token = document.getElementById('token').value;
            const owner = document.getElementById('owner').value;
            const repo = document.getElementById('repo').value;
            const path = document.getElementById('path').value;
            const contentType = document.getElementById('contentType').value;

            const url = `https://api.github.com/repos/${owner}/${repo}/contents/${path}`;

            let content;
            if (contentType === 'text') {
                content = document.getElementById('content').value;
                uploadToGitHub(url, token, btoa(content));
            } else {
                const file = document.getElementById('image').files[0];
                if (file) {
                    const reader = new FileReader();
                    reader.onload = function(e) {
                        content = e.target.result.split(',')[1]; // Get base64 data
                        uploadToGitHub(url, token, content);
                    };
                    reader.readAsDataURL(file);
                } else {
                    document.getElementById('result').innerHTML = 'Please select an image file.';
                }
            }
        });

        function uploadToGitHub(url, token, content) {
            fetch(url, {
                method: 'PUT',
                headers: {
                    'Authorization': `token ${token}`,
                    'Content-Type': 'application/json',
                },
                body: JSON.stringify({
                    message: 'Create file/image via API',
                    content: content
                })
            })
            .then(response => response.json())
            .then(data => {
                if (data.content) {
                    document.getElementById('result').innerHTML = `File/Image created successfully. <a href="${data.content.html_url}" target="_blank">View file</a>`;
                } else {
                    document.getElementById('result').innerHTML = `Error: ${JSON.stringify(data)}`;
                }
            })
            .catch(error => {
                document.getElementById('result').innerHTML = `Error: ${error.message}`;
            });
        }
    </script>
</body>
</html>

I've added CSS to improve the visual appearance and user experience of the page. Here are the key styling changes:

  1. Overall Layout:

    • Set a maximum width for the body and centered it.
    • Added a light gray background to the body for contrast.
  2. Typography:

    • Used Arial as the primary font with a fallback to sans-serif.
    • Improved line height for better readability.
    • Styled the heading with a different color and centered it.
  3. Form Styling:

    • Added a white background to the form.
    • Applied padding and rounded corners to the form.
    • Added a subtle box shadow for depth.
  4. Input Fields:

    • Styled all input fields, select dropdowns, and textareas consistently.
    • Added some padding and rounded corners to input fields.
    • Made input fields expand to full width of their container.
  5. Buttons:

    • Styled buttons with a blue background and white text.
    • Added hover effects to buttons for better interactivity.
    • Styled the "Clear Image" button differently (red) to distinguish its action.
  6. Result Display:

    • Added styling to the result div to make successful messages stand out.
    • Used a light green background with darker text for success messages.

These CSS changes make the page more visually appealing and easier to use. The form elements are now more clearly defined, and the overall layout is more balanced. The color scheme is simple and professional, using mainly blue, white, and gray with touches of green and red for specific elements.

Is there anything specific about the styling you'd like me to explain further or modify?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment