@rmdes/indiekit-endpoint-microsub 1.0.39 → 1.0.40

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1184,10 +1184,10 @@ export async function timeline(request, response) {
1184
1184
  // Get channels with colors for filtering UI and item decoration
1185
1185
  const channelList = await getChannelsWithColors(application, userId);
1186
1186
 
1187
- // Build channel lookup map (ObjectId string -> { name, color })
1187
+ // Build channel lookup map (ObjectId string -> { name, color, uid })
1188
1188
  const channelMap = new Map();
1189
1189
  for (const ch of channelList) {
1190
- channelMap.set(ch._id.toString(), { name: ch.name, color: ch.color });
1190
+ channelMap.set(ch._id.toString(), { name: ch.name, color: ch.color, uid: ch.uid });
1191
1191
  }
1192
1192
 
1193
1193
  // Parse excluded channel IDs from query params
@@ -1223,6 +1223,7 @@ export async function timeline(request, response) {
1223
1223
  if (info) {
1224
1224
  item._channelName = info.name;
1225
1225
  item._channelColor = info.color;
1226
+ item._channelUid = info.uid;
1226
1227
  }
1227
1228
  }
1228
1229
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rmdes/indiekit-endpoint-microsub",
3
- "version": "1.0.39",
3
+ "version": "1.0.40",
4
4
  "description": "Microsub endpoint for Indiekit. Enables subscribing to feeds and reading content using the Microsub protocol.",
5
5
  "keywords": [
6
6
  "indiekit",
@@ -202,6 +202,7 @@
202
202
  class="item-actions__button item-actions__mark-read"
203
203
  data-action="mark-read"
204
204
  data-item-id="{{ item._id }}"
205
+ {% if item._channelUid %}data-channel-uid="{{ item._channelUid }}"{% endif %}
205
206
  title="Mark as read">
206
207
  {{ icon("checkboxChecked") }}
207
208
  <span class="visually-hidden">Mark read</span>
@@ -95,6 +95,61 @@
95
95
  break;
96
96
  }
97
97
  });
98
+
99
+ // Handle individual mark-read buttons
100
+ const microsubApiUrl = '{{ baseUrl }}'.replace(/\/reader$/, '');
101
+
102
+ timeline.addEventListener('click', async (e) => {
103
+ const button = e.target.closest('.item-actions__mark-read');
104
+ if (!button) return;
105
+
106
+ e.preventDefault();
107
+ e.stopPropagation();
108
+
109
+ const itemId = button.dataset.itemId;
110
+ const channelUid = button.dataset.channelUid;
111
+ if (!itemId || !channelUid) return;
112
+
113
+ button.disabled = true;
114
+
115
+ try {
116
+ const formData = new URLSearchParams();
117
+ formData.append('action', 'timeline');
118
+ formData.append('method', 'mark_read');
119
+ formData.append('channel', channelUid);
120
+ formData.append('entry', itemId);
121
+
122
+ const response = await fetch(microsubApiUrl, {
123
+ method: 'POST',
124
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
125
+ body: formData.toString(),
126
+ credentials: 'same-origin'
127
+ });
128
+
129
+ if (response.ok) {
130
+ const card = button.closest('.item-card');
131
+ if (card) {
132
+ card.style.transition = 'opacity 0.3s ease, transform 0.3s ease';
133
+ card.style.opacity = '0';
134
+ card.style.transform = 'translateX(-20px)';
135
+ setTimeout(() => {
136
+ const wrapper = card.closest('.timeline-view__item');
137
+ if (wrapper) wrapper.remove();
138
+ else card.remove();
139
+ if (timeline.querySelectorAll('.item-card').length === 0) {
140
+ location.reload();
141
+ }
142
+ }, 300);
143
+ }
144
+ } else {
145
+ console.error('Failed to mark item as read');
146
+ button.disabled = false;
147
+ }
148
+ } catch (error) {
149
+ console.error('Error marking item as read:', error);
150
+ button.disabled = false;
151
+ }
152
+ });
98
153
  }
99
154
  </script>
100
155
  {% endblock %}