this repo has no description
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

shit

cpfiffer aae7ffda 038b0c3f

+219 -221
-172
app.js
··· 1 - document.addEventListener('DOMContentLoaded', () => { 2 - console.log("DOMContentLoaded event fired for app.js"); // New diagnostic log 3 - 4 - const initializeApp = () => { 5 - // Main application code 6 - let currentCursor = null; 7 - const recordsContainer = document.getElementById("recordsContainer"); 8 - const loadMoreButton = document.getElementById("loadMoreButton"); 9 - const loadButton = document.getElementById("loadButton"); 10 - const repoInput = document.getElementById("repoInput"); 11 - 12 - // Initialize the AT Protocol client - FIXED VERSION // lol claude wrote that 13 - const agent = new window.AtprotoApi.AtpAgent({ 14 - service: "https://bsky.social", 15 - }); 16 - console.log("ATProto Agent initialized:", agent); // Diagnostic log 17 - 18 - // Event listeners 19 - loadButton.addEventListener("click", () => { 20 - console.log("Load button clicked"); // Diagnostic log 21 - const repo = repoInput.value.trim(); 22 - if (!repo) { 23 - alert("Please enter a valid repository DID or handle"); 24 - return; 25 - } 26 - 27 - // Clear previous records and reset cursor 28 - recordsContainer.innerHTML = ""; 29 - currentCursor = null; 30 - loadMoreButton.style.display = "none"; 31 - 32 - // Load the first batch of records 33 - loadRecords(repo); 34 - }); 35 - 36 - loadMoreButton.addEventListener("click", () => { 37 - loadRecords(repoInput.value.trim()); 38 - }); 39 - 40 - // Function to load records from the repository 41 - async function loadRecords(repo) { 42 - console.log("loadRecords called with repo:", repo); // Diagnostic log 43 - try { 44 - loadButton.disabled = true; 45 - loadMoreButton.disabled = true; 46 - loadMoreButton.textContent = "Loading..."; 47 - console.log("Attempting to list records for repo:", repo, "with cursor:", currentCursor); // Diagnostic log 48 - 49 - // Call the AT Protocol API to list records 50 - const response = await agent.com.atproto.repo.listRecords({ 51 - repo: repo, 52 - collection: "me.comind.blip.thought", 53 - limit: 10, 54 - cursor: currentCursor, 55 - }); 56 - 57 - // Update the cursor for pagination 58 - currentCursor = response.data.cursor; 59 - 60 - // Show or hide the "Load More" button based on cursor availability 61 - if (currentCursor) { 62 - loadMoreButton.style.display = "block"; 63 - } else { 64 - loadMoreButton.style.display = "none"; 65 - } 66 - 67 - // Render the records 68 - renderRecords(response.data.records); 69 - } catch (error) { 70 - console.error("Error loading records:", error); 71 - alert(`Error: ${error.message || "Failed to load records"}`); 72 - } finally { 73 - loadButton.disabled = false; 74 - loadMoreButton.disabled = false; 75 - loadMoreButton.textContent = "Load More"; 76 - } 77 - } 78 - 79 - // Function to render the records 80 - function renderRecords(records) { 81 - if (records.length === 0) { 82 - recordsContainer.innerHTML += 83 - '<div class="alert alert-info">No records found</div>'; 84 - return; 85 - } 86 - 87 - records.forEach((record) => { 88 - const { value } = record; 89 - const thoughtEl = document.createElement("div"); 90 - thoughtEl.className = "card thought-card p-3"; 91 - 92 - // Format the date/time 93 - const createdAt = new Date(value.createdAt); 94 - const formattedDate = createdAt.toLocaleString(); 95 - 96 - // Get the thought data 97 - const thought = value.generated; 98 - 99 - // Build the HTML 100 - thoughtEl.innerHTML = ` 101 - <div class="card-body"> 102 - <div class="d-flex justify-content-between align-items-start"> 103 - <span class="thought-type">${thought.thoughtType}</span> 104 - <small class="text-muted">${formattedDate}</small> 105 - </div> 106 - 107 - ${thought.context ? `<p class="text-muted mb-2">${thought.context}</p>` : ""} 108 - 109 - <p class="card-text">${thought.text}</p> 110 - 111 - ${ 112 - thought.evidence.length > 0 113 - ? ` 114 - <div class="mt-3"> 115 - <h6>Evidence:</h6> 116 - <div class="evidence-list"> 117 - ${thought.evidence 118 - .map( 119 - (item) => ` 120 - <div class="evidence-item">${item}</div> 121 - `, 122 - ) 123 - .join("")} 124 - </div> 125 - </div> 126 - ` 127 - : "" 128 - } 129 - 130 - ${ 131 - thought.alternatives.length > 0 132 - ? ` 133 - <div class="mt-3"> 134 - <h6>Alternative Thoughts:</h6> 135 - <div class="alternatives-list"> 136 - ${thought.alternatives 137 - .map( 138 - (item) => ` 139 - <div class="alternative-item">${item}</div> 140 - `, 141 - ) 142 - .join("")} 143 - </div> 144 - </div> 145 - ` 146 - : "" 147 - } 148 - 149 - <div class="mt-2"> 150 - <small class="text-muted">URI: ${record.uri}</small> 151 - </div> 152 - </div> 153 - `; 154 - 155 - recordsContainer.appendChild(thoughtEl); 156 - }); 157 - } 158 - }; 159 - 160 - const checkApiReady = () => { 161 - console.log("checkApiReady called. Checking for window.AtprotoApi and window.AtprotoApi.AtpAgent..."); // New diagnostic log 162 - if (window.AtprotoApi && window.AtprotoApi.AtpAgent) { 163 - console.log("AtprotoApi is ready, calling initializeApp."); // New diagnostic log 164 - initializeApp(); 165 - } else { 166 - console.log("AtprotoApi not ready, polling again in 50ms. window.AtprotoApi:", window.AtprotoApi); // New diagnostic log 167 - setTimeout(checkApiReady, 50); // Poll every 50ms 168 - } 169 - }; 170 - 171 - checkApiReady(); 172 - });
+219 -49
index.html
··· 3 3 <head> 4 4 <meta charset="UTF-8" /> 5 5 <meta name="viewport" content="width=device-width, initial-scale=1.0" /> 6 - <title>Thought Records Viewer</title> 7 - <link 8 - href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" 9 - rel="stylesheet" 10 - /> 6 + <title>Blips Viewer</title> 11 7 <style> 12 - .thought-card { 13 - margin-bottom: 20px; 14 - border-left: 4px solid #0d6efd; 8 + body { 9 + font-family: Arial, sans-serif; 10 + max-width: 800px; 11 + margin: 0 auto; 12 + padding: 20px; 15 13 } 16 - .thought-type { 17 - display: inline-block; 18 - padding: 2px 8px; 19 - border-radius: 12px; 20 - background-color: #e9ecef; 21 - margin-bottom: 8px; 14 + textarea { 15 + width: 100%; 16 + height: 200px; 17 + margin-bottom: 10px; 18 + } 19 + button { 20 + padding: 8px 16px; 21 + margin-right: 10px; 22 + } 23 + .card { 24 + border: 1px solid #ccc; 25 + border-radius: 4px; 26 + padding: 15px; 27 + margin-top: 20px; 22 28 } 23 29 .evidence-item, 24 30 .alternative-item { 25 - border-left: 2px solid #6c757d; 26 - padding-left: 10px; 31 + margin-left: 20px; 27 32 margin-bottom: 5px; 28 33 } 34 + .meta { 35 + color: #666; 36 + font-size: 0.9em; 37 + margin-bottom: 10px; 38 + } 39 + .error { 40 + color: red; 41 + font-weight: bold; 42 + } 29 43 </style> 30 44 </head> 31 45 <body> 32 - <div class="container mt-4"> 33 - <h1>Thought Records Viewer</h1> 34 - <div class="mb-3"> 35 - <label for="repoInput" class="form-label" 36 - >Repository (DID or handle)</label 37 - > 38 - <input 39 - type="text" 40 - class="form-control" 41 - id="repoInput" 42 - placeholder="Enter DID or handle (e.g., did:plc:abcde or user.bsky.social)" 43 - /> 44 - </div> 45 - <button id="loadButton" class="btn btn-primary mb-4"> 46 - Load Records 47 - </button> 46 + <h1>Blips Viewer</h1> 48 47 49 - <div id="recordsContainer"></div> 50 - 51 - <div class="d-flex justify-content-center mt-3 mb-5"> 52 - <button 53 - id="loadMoreButton" 54 - class="btn btn-secondary" 55 - style="display: none" 56 - > 57 - Load More 58 - </button> 59 - </div> 48 + <h2>Input JSON</h2> 49 + <textarea 50 + id="jsonInput" 51 + placeholder="Paste your JSON here..." 52 + ></textarea> 53 + <div> 54 + <button id="parseBtn">Parse JSON</button> 55 + <button id="clearBtn">Clear</button> 56 + <button id="sampleThoughtBtn">Load Sample Thought</button> 57 + <button id="sampleEmotionBtn">Load Sample Emotion</button> 60 58 </div> 61 59 62 - <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script> 63 - <script src="https://cdn.jsdelivr.net/npm/@atproto/api@latest/dist/bundle.js"></script> 60 + <div id="output" class="card" style="display: none"></div> 61 + <div id="error" class="error" style="display: none"></div> 62 + 64 63 <script> 65 - console.log("Inline script in index.html executing."); 66 - console.log("All keys on window object (from index.html):", Object.keys(window).filter((key) => true)); 67 - console.log("Checking for window.AtprotoApi in index.html inline script:", window.AtprotoApi); 64 + // Sample data 65 + const sampleThought = { 66 + uri: "at://did:plc:gfrmhdmjvxn2sjedzboeudef/me.comind.blip.thought/3louhnsmths2i", 67 + cid: "bafyreigp2jkulmrupo2xtnawrptrc6kieoorpvyzzuhu2ktrpeo3ybjuza", 68 + value: { 69 + $type: "me.comind.blip.thought", 70 + createdAt: "2025-05-10T20:00:40.009657", 71 + generated: { 72 + text: "If visual posts with personal, relatable themes continue to prove engaging on Bluesky, we may see more users adopt a similar content strategy.", 73 + context: null, 74 + evidence: [ 75 + "June Martin's anniversary dress post was seen as positive and shares personal content", 76 + "Cameron Pfiffer likely liked the post because it was engaging and relatable", 77 + "Other posts producing engagement often focus on personal life events and themes", 78 + ], 79 + thoughtType: "prediction", 80 + alternatives: [ 81 + "Predicting user behavior is inherently uncertain and may not pan out", 82 + "Alternative content strategies like hard news or abstract ideas could gain traction", 83 + ], 84 + }, 85 + }, 86 + }; 87 + 88 + const sampleEmotion = { 89 + uri: "at://did:plc:gfrmhdmjvxn2sjedzboeudef/me.comind.blip.emotion/3lohfgj4voo23", 90 + cid: "bafyreiehbt5ktvp64s7jc44nqc7xycoigdqhxhnzle5oek7xei2bwx2pqa", 91 + value: { 92 + $type: "me.comind.blip.emotion", 93 + createdAt: "2025-05-05T15:16:11.096135", 94 + generated: { 95 + text: "I feel hope that Bluesky's external achievements will inspire further progress and innovation in the decentralized social media space. This success story gives me optimism for the future.", 96 + emotionType: "hope", 97 + }, 98 + }, 99 + }; 100 + 101 + // DOM elements 102 + const jsonInput = document.getElementById("jsonInput"); 103 + const parseBtn = document.getElementById("parseBtn"); 104 + const clearBtn = document.getElementById("clearBtn"); 105 + const sampleThoughtBtn = 106 + document.getElementById("sampleThoughtBtn"); 107 + const sampleEmotionBtn = 108 + document.getElementById("sampleEmotionBtn"); 109 + const output = document.getElementById("output"); 110 + const errorEl = document.getElementById("error"); 111 + 112 + // Event listeners 113 + parseBtn.addEventListener("click", parseAndDisplay); 114 + clearBtn.addEventListener("click", clearAll); 115 + sampleThoughtBtn.addEventListener("click", () => 116 + loadSample(sampleThought), 117 + ); 118 + sampleEmotionBtn.addEventListener("click", () => 119 + loadSample(sampleEmotion), 120 + ); 121 + 122 + function loadSample(sample) { 123 + jsonInput.value = JSON.stringify(sample, null, 2); 124 + parseAndDisplay(); 125 + } 126 + 127 + function clearAll() { 128 + jsonInput.value = ""; 129 + output.style.display = "none"; 130 + errorEl.style.display = "none"; 131 + } 132 + 133 + function parseAndDisplay() { 134 + try { 135 + errorEl.style.display = "none"; 136 + const data = JSON.parse(jsonInput.value); 137 + 138 + // Validate basic structure 139 + if (!data.uri || !data.cid || !data.value) { 140 + throw new Error( 141 + "Invalid data structure. Expected uri, cid, and value properties.", 142 + ); 143 + } 144 + 145 + const type = data.value.$type; 146 + if (!type) { 147 + throw new Error("Missing $type in the value object."); 148 + } 149 + 150 + // Render based on type 151 + if (type === "me.comind.blip.thought") { 152 + renderThought(data); 153 + } else if (type === "me.comind.blip.emotion") { 154 + renderEmotion(data); 155 + } else { 156 + throw new Error( 157 + `Unknown type: ${type}. Expected me.comind.blip.thought or me.comind.blip.emotion.`, 158 + ); 159 + } 160 + 161 + output.style.display = "block"; 162 + } catch (err) { 163 + errorEl.textContent = `Error: ${err.message}`; 164 + errorEl.style.display = "block"; 165 + output.style.display = "none"; 166 + } 167 + } 168 + 169 + function renderThought(data) { 170 + const thought = data.value; 171 + const generated = thought.generated; 172 + 173 + let html = ` 174 + <div class="meta"> 175 + <div><strong>Type:</strong> ${thought.$type}</div> 176 + <div><strong>URI:</strong> ${data.uri}</div> 177 + <div><strong>CID:</strong> ${data.cid}</div> 178 + <div><strong>Created:</strong> ${formatDate(thought.createdAt)}</div> 179 + <div><strong>Thought Type:</strong> ${generated.thoughtType}</div> 180 + </div> 181 + <div class="content"> 182 + <p>${generated.text}</p> 183 + ${generated.context ? `<p><strong>Context:</strong> ${generated.context}</p>` : ""} 184 + </div>`; 185 + 186 + if (generated.evidence && generated.evidence.length > 0) { 187 + html += `<div class="evidence"> 188 + <h3>Evidence:</h3> 189 + <ul>`; 190 + generated.evidence.forEach((item) => { 191 + html += `<li class="evidence-item">${item}</li>`; 192 + }); 193 + html += `</ul></div>`; 194 + } 195 + 196 + if ( 197 + generated.alternatives && 198 + generated.alternatives.length > 0 199 + ) { 200 + html += `<div class="alternatives"> 201 + <h3>Alternatives:</h3> 202 + <ul>`; 203 + generated.alternatives.forEach((item) => { 204 + html += `<li class="alternative-item">${item}</li>`; 205 + }); 206 + html += `</ul></div>`; 207 + } 208 + 209 + output.innerHTML = html; 210 + } 211 + 212 + function renderEmotion(data) { 213 + const emotion = data.value; 214 + const generated = emotion.generated; 215 + 216 + let html = ` 217 + <div class="meta"> 218 + <div><strong>Type:</strong> ${emotion.$type}</div> 219 + <div><strong>URI:</strong> ${data.uri}</div> 220 + <div><strong>CID:</strong> ${data.cid}</div> 221 + <div><strong>Created:</strong> ${formatDate(emotion.createdAt)}</div> 222 + <div><strong>Emotion Type:</strong> ${generated.emotionType}</div> 223 + </div> 224 + <div class="content"> 225 + <p>${generated.text}</p> 226 + </div>`; 227 + 228 + output.innerHTML = html; 229 + } 230 + 231 + function formatDate(dateString) { 232 + try { 233 + const date = new Date(dateString); 234 + return date.toLocaleString(); 235 + } catch (e) { 236 + return dateString; // Return as-is if parsing fails 237 + } 238 + } 68 239 </script> 69 - <script type="module" src="app.js"></script> 70 240 </body> 71 241 </html>