@rmdes/indiekit-endpoint-homepage 1.0.0 → 1.0.2

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.
package/index.js CHANGED
@@ -138,6 +138,38 @@ export default class HomepageEndpoint {
138
138
  defaultConfig: {},
139
139
  configSchema: {},
140
140
  },
141
+ {
142
+ id: "social-activity",
143
+ label: "Social Activity",
144
+ description: "Bluesky and Mastodon feeds",
145
+ icon: "message-circle",
146
+ defaultConfig: {},
147
+ configSchema: {},
148
+ },
149
+ {
150
+ id: "github-repos",
151
+ label: "GitHub Projects",
152
+ description: "GitHub repositories and activity",
153
+ icon: "github",
154
+ defaultConfig: {},
155
+ configSchema: {},
156
+ },
157
+ {
158
+ id: "funkwhale",
159
+ label: "Listening",
160
+ description: "Funkwhale now playing and stats",
161
+ icon: "music",
162
+ defaultConfig: {},
163
+ configSchema: {},
164
+ },
165
+ {
166
+ id: "blogroll",
167
+ label: "Blogroll",
168
+ description: "Blog recommendations",
169
+ icon: "list",
170
+ defaultConfig: {},
171
+ configSchema: {},
172
+ },
141
173
  ];
142
174
  }
143
175
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rmdes/indiekit-endpoint-homepage",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "Homepage builder endpoint for Indiekit. Configure layout, sections, and sidebar widgets from the admin UI.",
5
5
  "keywords": [
6
6
  "indiekit",
@@ -284,10 +284,67 @@
284
284
  </form>
285
285
 
286
286
  <script>
287
+ // Label lookup maps for rendering
288
+ const sectionLabels = {
289
+ {% for section in sections %}'{{ section.id }}': '{{ section.label }}'{% if not loop.last %}, {% endif %}{% endfor %}
290
+ };
291
+ const widgetLabels = {
292
+ {% for widget in widgets %}'{{ widget.id }}': '{{ widget.label }}'{% if not loop.last %}, {% endif %}{% endfor %}
293
+ };
294
+
287
295
  // Parse current sections and sidebar from hidden inputs
288
296
  let sections = JSON.parse(document.getElementById('sections-json').value || '[]');
289
297
  let sidebar = JSON.parse(document.getElementById('sidebar-json').value || '[]');
290
298
 
299
+ function createItemElement(type, labels, removeFn) {
300
+ const li = document.createElement('li');
301
+ li.className = 'hp-section-item';
302
+ li.dataset.type = type;
303
+
304
+ const info = document.createElement('div');
305
+ info.className = 'hp-section-item__info';
306
+
307
+ const name = document.createElement('span');
308
+ name.className = 'hp-section-item__name';
309
+ name.textContent = labels[type] || type;
310
+
311
+ const typeSpan = document.createElement('span');
312
+ typeSpan.className = 'hp-section-item__type';
313
+ typeSpan.textContent = type;
314
+
315
+ info.appendChild(name);
316
+ info.appendChild(typeSpan);
317
+
318
+ const actions = document.createElement('div');
319
+ actions.className = 'hp-section-item__actions';
320
+
321
+ const btn = document.createElement('button');
322
+ btn.type = 'button';
323
+ btn.className = 'button button--small button--secondary';
324
+ btn.textContent = 'Remove';
325
+ btn.addEventListener('click', function() { removeFn(this); });
326
+
327
+ actions.appendChild(btn);
328
+ li.appendChild(info);
329
+ li.appendChild(actions);
330
+
331
+ return li;
332
+ }
333
+
334
+ function renderList(listEl, items, labels, removeFn, emptyText) {
335
+ listEl.textContent = '';
336
+ if (items.length === 0) {
337
+ const li = document.createElement('li');
338
+ li.className = 'hp-empty';
339
+ li.textContent = emptyText;
340
+ listEl.appendChild(li);
341
+ } else {
342
+ items.forEach(function(item) {
343
+ listEl.appendChild(createItemElement(item.type, labels, removeFn));
344
+ });
345
+ }
346
+ }
347
+
291
348
  function addSection(id, label) {
292
349
  sections.push({ type: id, config: {} });
293
350
  updateSectionsList();
@@ -296,14 +353,17 @@
296
353
  function removeSection(button) {
297
354
  const item = button.closest('.hp-section-item');
298
355
  const type = item.dataset.type;
299
- sections = sections.filter(s => s.type !== type);
356
+ sections = sections.filter(function(s) { return s.type !== type; });
300
357
  updateSectionsList();
301
358
  }
302
359
 
303
360
  function updateSectionsList() {
304
361
  document.getElementById('sections-json').value = JSON.stringify(sections);
305
- // Reload to show updated list (simple approach)
306
- // In a more sophisticated version, we'd update the DOM directly
362
+ renderList(
363
+ document.getElementById('sections-list'),
364
+ sections, sectionLabels, removeSection,
365
+ '{{ __("homepage.sections.empty") }}'
366
+ );
307
367
  }
308
368
 
309
369
  function addWidget(id, label) {
@@ -314,36 +374,39 @@
314
374
  function removeWidget(button) {
315
375
  const item = button.closest('.hp-section-item');
316
376
  const type = item.dataset.type;
317
- sidebar = sidebar.filter(w => w.type !== type);
377
+ sidebar = sidebar.filter(function(w) { return w.type !== type; });
318
378
  updateWidgetsList();
319
379
  }
320
380
 
321
381
  function updateWidgetsList() {
322
382
  document.getElementById('sidebar-json').value = JSON.stringify(sidebar);
383
+ renderList(
384
+ document.getElementById('widgets-list'),
385
+ sidebar, widgetLabels, removeWidget,
386
+ '{{ __("homepage.sidebar.empty") }}'
387
+ );
323
388
  }
324
389
 
325
390
  // Layout selection
326
- document.querySelectorAll('.hp-layout-option').forEach(option => {
327
- option.addEventListener('click', () => {
328
- document.querySelectorAll('.hp-layout-option').forEach(o => o.classList.remove('selected'));
391
+ document.querySelectorAll('.hp-layout-option').forEach(function(option) {
392
+ option.addEventListener('click', function() {
393
+ document.querySelectorAll('.hp-layout-option').forEach(function(o) { o.classList.remove('selected'); });
329
394
  option.classList.add('selected');
330
395
  });
331
396
  });
332
397
 
333
- // Hero checkboxes - convert to JSON
398
+ // Hero checkboxes - convert to JSON on submit
334
399
  document.querySelector('form').addEventListener('submit', function(e) {
335
400
  const heroEnabled = document.querySelector('input[name="hero[enabled]"]').checked;
336
401
  const heroShowSocial = document.querySelector('input[name="hero[showSocial]"]').checked;
337
402
 
338
- // Create hidden input with hero JSON
339
403
  const heroInput = document.createElement('input');
340
404
  heroInput.type = 'hidden';
341
405
  heroInput.name = 'hero';
342
406
  heroInput.value = JSON.stringify({ enabled: heroEnabled, showSocial: heroShowSocial });
343
407
  this.appendChild(heroInput);
344
408
 
345
- // Remove the checkbox inputs
346
- document.querySelectorAll('input[name^="hero["]').forEach(i => i.name = '');
409
+ document.querySelectorAll('input[name^="hero["]').forEach(function(i) { i.name = ''; });
347
410
  });
348
411
  </script>
349
412
  {% endblock %}