Skip to content

SHU

digital communications

New year, new job

After what will be three months of babies, more babies, and an actually pretty decent stab at being a freelance writer [https://www.iainbroome.com/blog/that-was-the-week-that-was], from the beginning of January I’ll be back in full-time employment. Last week I was offered what I think is an exciting

/** * Micro.blog integration for Ghost using App Token (recommended approach) * To use this script: * 1. Go to your Ghost Admin Panel * 2. Navigate to Settings → Code Injection * 3. Paste this code in the "Site Footer" section * 4. Replace the placeholders with your actual values */ (function() { // Configuration const config = { microblogUsername: 'iainbroome', // Your micro.blog username appToken: '5FCF352BBF139DA801F8', // Your micro.blog app token (if using authenticated API) postsPerPage: 10, targetElement: '#microblog-posts' // The element where posts will be displayed }; // Only run on the micro.blog page if (!document.querySelector(config.targetElement)) { return; } // Styles const styles = ` .mb-container { margin: 2rem 0; } .mb-post { margin-bottom: 2rem; padding-bottom: 1.5rem; border-bottom: 1px solid var(--ghost-accent-color, #eee); } .mb-post:last-child { border-bottom: none; } .mb-date { font-size: 0.9rem; color: var(--ghost-secondary-color, #666); margin-bottom: 0.5rem; } .mb-content { margin-bottom: 0.5rem; } .mb-content img { max-width: 100%; border-radius: 4px; margin: 0.5rem 0; } .mb-link { font-size: 0.9rem; } .mb-link a { color: var(--ghost-accent-color, #1a73e8); text-decoration: none; } .mb-link a:hover { text-decoration: underline; } .mb-pagination { display: flex; justify-content: space-between; margin-top: 2rem; } .mb-pagination button { background-color: var(--ghost-accent-color, #1a73e8); color: white; border: none; padding: 8px 16px; border-radius: 4px; cursor: pointer; } .mb-pagination button:disabled { background-color: #ccc; cursor: not-allowed; } .mb-error { color: #d32f2f; padding: 15px; border: 1px solid #ffd7d7; background-color: #fff8f8; border-radius: 4px; } .mb-loading { text-align: center; padding: 20px; color: var(--ghost-secondary-color, #666); } `; // Add styles to head const styleElement = document.createElement('style'); styleElement.textContent = styles; document.head.appendChild(styleElement); // State let currentPage = 1; // DOM elements const targetElement = document.querySelector(config.targetElement); if (!targetElement) return; // Create container elements const container = document.createElement('div'); container.className = 'mb-container'; const postsContainer = document.createElement('div'); postsContainer.className = 'mb-posts'; const paginationContainer = document.createElement('div'); paginationContainer.className = 'mb-pagination'; paginationContainer.innerHTML = ` `; container.appendChild(postsContainer); container.appendChild(paginationContainer); targetElement.appendChild(container); const prevButton = paginationContainer.querySelector('.mb-prev'); const nextButton = paginationContainer.querySelector('.mb-next'); // Fetch posts function fetchPosts(page = 1) { postsContainer.innerHTML = '
Loading micro.blog posts...
'; let endpoint, headers = {}; if (config.appToken) { // Authenticated API (preferred) endpoint = `https://micro.blog/posts?count=${config.postsPerPage}&page=${page}`; headers = { 'Authorization': `Bearer ${config.appToken}` }; } else { // Public JSON feed (limited) endpoint = `https://micro.blog/posts/${config.microblogUsername}`; } fetch(endpoint, { headers }) .then(response => { if (!response.ok) { throw new Error(`Failed to fetch posts (${response.status})`); } return response.json(); }) .then(data => { displayPosts(data.items || []); updatePagination((data.items || []).length < config.postsPerPage); }) .catch(error => { postsContainer.innerHTML = `

Error loading micro.blog posts: ${error.message}

Note: For best results, obtain an app token from micro.blog.

`; }); } // Display posts function displayPosts(posts) { if (!posts || posts.length === 0) { postsContainer.innerHTML = '

No micro.blog posts found.

'; return; } postsContainer.innerHTML = ''; posts.forEach(post => { const postDate = new Date(post.date_published); const postElement = document.createElement('div'); postElement.className = 'mb-post'; let postHTML = `
${formatDate(postDate)}
${post.content_html}
`; if (post.url) { postHTML += ` `; } postElement.innerHTML = postHTML; postsContainer.appendChild(postElement); }); } // Update pagination buttons function updatePagination(isLastPage) { prevButton.disabled = currentPage === 1; nextButton.disabled = isLastPage; } // Format date function formatDate(date) { const options = { year: 'numeric', month: 'long', day: 'numeric', hour: '2-digit', minute: '2-digit' }; return date.toLocaleDateString(undefined, options); } // Event listeners for pagination prevButton.addEventListener('click', function() { if (currentPage > 1) { currentPage--; fetchPosts(currentPage); scrollToTop(); } }); nextButton.addEventListener('click', function() { currentPage++; fetchPosts(currentPage); scrollToTop(); }); // Scroll to top of posts container function scrollToTop() { container.scrollIntoView({ behavior: 'smooth' }); } // Initial fetch fetchPosts(); })();