@fifthbell/brokaw 0.1.46 → 0.1.47
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/package.json
CHANGED
|
@@ -10,10 +10,12 @@
|
|
|
10
10
|
</div>
|
|
11
11
|
<div id='media-status' class='border border-slate-200 bg-white p-6 text-sm text-slate-600 dark:border-slate-800 dark:bg-slate-900 dark:text-slate-300'>Loading photos.</div>
|
|
12
12
|
<div id='media-grid' class='hidden grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4'></div>
|
|
13
|
+
<nav id='media-pagination' aria-label='Pagination' class='mt-8 hidden items-center justify-center gap-6'></nav>
|
|
13
14
|
</section>
|
|
14
15
|
</main>
|
|
15
16
|
<script>
|
|
16
17
|
(function () {
|
|
18
|
+
var PAGE_SIZE = 48;
|
|
17
19
|
var page = document.querySelector('[data-media-page]');
|
|
18
20
|
if (!page) return;
|
|
19
21
|
|
|
@@ -21,7 +23,9 @@
|
|
|
21
23
|
var meta = document.getElementById('media-meta');
|
|
22
24
|
var status = document.getElementById('media-status');
|
|
23
25
|
var grid = document.getElementById('media-grid');
|
|
26
|
+
var pagination = document.getElementById('media-pagination');
|
|
24
27
|
var refresh = document.getElementById('media-refresh');
|
|
28
|
+
var loadedData = null;
|
|
25
29
|
|
|
26
30
|
function text(value, fallback) {
|
|
27
31
|
if (typeof value !== 'string') return fallback || '';
|
|
@@ -60,27 +64,104 @@
|
|
|
60
64
|
status.textContent = message;
|
|
61
65
|
status.classList.remove('hidden');
|
|
62
66
|
grid.classList.add('hidden');
|
|
67
|
+
pagination.classList.add('hidden');
|
|
68
|
+
pagination.classList.remove('flex');
|
|
63
69
|
}
|
|
64
70
|
|
|
65
71
|
function imageUrl(item) {
|
|
66
72
|
return text(item && (item.url || item.jpgUrl || item.originalUrl), '');
|
|
67
73
|
}
|
|
68
74
|
|
|
75
|
+
function currentPageFromUrl() {
|
|
76
|
+
var value = new URL(window.location.href).searchParams.get('page') || '1';
|
|
77
|
+
var pageNumber = parseInt(value, 10);
|
|
78
|
+
return Number.isFinite(pageNumber) && pageNumber > 0 ? pageNumber : 1;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function pageHref(pageNumber) {
|
|
82
|
+
var url = new URL(window.location.href);
|
|
83
|
+
if (pageNumber <= 1) {
|
|
84
|
+
url.searchParams.delete('page');
|
|
85
|
+
} else {
|
|
86
|
+
url.searchParams.set('page', String(pageNumber));
|
|
87
|
+
}
|
|
88
|
+
return url.pathname + url.search + url.hash;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function paginationPages(currentPage, totalPages) {
|
|
92
|
+
var pages = [];
|
|
93
|
+
var lastAdded = 0;
|
|
94
|
+
|
|
95
|
+
function addPage(pageNumber) {
|
|
96
|
+
if (pageNumber < 1 || pageNumber > totalPages || pageNumber === lastAdded) return;
|
|
97
|
+
if (lastAdded && pageNumber > lastAdded + 1) pages.push({ ellipsis: true });
|
|
98
|
+
pages.push({ label: pageNumber, page: pageNumber, current: pageNumber === currentPage });
|
|
99
|
+
lastAdded = pageNumber;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
addPage(1);
|
|
103
|
+
for (var pageNumber = currentPage - 2; pageNumber <= currentPage + 2; pageNumber += 1) {
|
|
104
|
+
addPage(pageNumber);
|
|
105
|
+
}
|
|
106
|
+
addPage(totalPages);
|
|
107
|
+
|
|
108
|
+
return pages;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function renderPagination(currentPage, totalPages) {
|
|
112
|
+
if (totalPages <= 1) {
|
|
113
|
+
pagination.innerHTML = '';
|
|
114
|
+
pagination.classList.add('hidden');
|
|
115
|
+
pagination.classList.remove('flex');
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
var prev = currentPage > 1
|
|
120
|
+
? '<a href="' + escapeHtml(pageHref(currentPage - 1)) + '" class="inline-flex items-center gap-1 text-sm font-medium text-slate-500 transition-colors hover:text-[#b21100] dark:text-slate-400 dark:hover:text-[#ff2e1a]" aria-label="Previous page"><svg viewBox="0 0 20 20" fill="currentColor" class="h-4 w-4" aria-hidden="true"><path fill-rule="evenodd" d="M11.78 5.22a.75.75 0 0 1 0 1.06L8.06 10l3.72 3.72a.75.75 0 1 1-1.06 1.06l-4.25-4.25a.75.75 0 0 1 0-1.06l4.25-4.25a.75.75 0 0 1 1.06 0Z" clip-rule="evenodd"/></svg>Prev</a>'
|
|
121
|
+
: '<span class="inline-flex items-center gap-1 text-sm font-medium text-slate-300 dark:text-slate-700" aria-disabled="true"><svg viewBox="0 0 20 20" fill="currentColor" class="h-4 w-4" aria-hidden="true"><path fill-rule="evenodd" d="M11.78 5.22a.75.75 0 0 1 0 1.06L8.06 10l3.72 3.72a.75.75 0 1 1-1.06 1.06l-4.25-4.25a.75.75 0 0 1 0-1.06l4.25-4.25a.75.75 0 0 1 1.06 0Z" clip-rule="evenodd"/></svg>Prev</span>';
|
|
122
|
+
|
|
123
|
+
var items = paginationPages(currentPage, totalPages)
|
|
124
|
+
.map(function (item) {
|
|
125
|
+
if (item.ellipsis) {
|
|
126
|
+
return '<li><span class="inline-flex h-9 w-9 items-center justify-center text-sm text-slate-400 dark:text-slate-500">...</span></li>';
|
|
127
|
+
}
|
|
128
|
+
if (item.current) {
|
|
129
|
+
return '<li><span aria-current="page" class="inline-flex h-9 w-9 items-center justify-center border-b-2 border-[#b21100] text-sm font-bold text-[#b21100] dark:border-[#ff2e1a] dark:text-[#ff2e1a]">' + item.label + '</span></li>';
|
|
130
|
+
}
|
|
131
|
+
return '<li><a href="' + escapeHtml(pageHref(item.page)) + '" class="inline-flex h-9 w-9 items-center justify-center text-sm font-medium text-slate-600 transition-colors hover:text-[#b21100] dark:text-slate-300 dark:hover:text-[#ff2e1a]">' + item.label + '</a></li>';
|
|
132
|
+
})
|
|
133
|
+
.join('');
|
|
134
|
+
|
|
135
|
+
var next = currentPage < totalPages
|
|
136
|
+
? '<a href="' + escapeHtml(pageHref(currentPage + 1)) + '" class="inline-flex items-center gap-1 text-sm font-medium text-slate-500 transition-colors hover:text-[#b21100] dark:text-slate-400 dark:hover:text-[#ff2e1a]" aria-label="Next page">Next<svg viewBox="0 0 20 20" fill="currentColor" class="h-4 w-4" aria-hidden="true"><path fill-rule="evenodd" d="M8.22 5.22a.75.75 0 0 1 1.06 0l4.25 4.25a.75.75 0 0 1 0 1.06l-4.25 4.25a.75.75 0 1 1-1.06-1.06L11.94 10 8.22 6.28a.75.75 0 0 1 0-1.06Z" clip-rule="evenodd"/></svg></a>'
|
|
137
|
+
: '<span class="inline-flex items-center gap-1 text-sm font-medium text-slate-300 dark:text-slate-700" aria-disabled="true">Next<svg viewBox="0 0 20 20" fill="currentColor" class="h-4 w-4" aria-hidden="true"><path fill-rule="evenodd" d="M8.22 5.22a.75.75 0 0 1 1.06 0l4.25 4.25a.75.75 0 0 1 0 1.06l-4.25 4.25a.75.75 0 1 1-1.06-1.06L11.94 10 8.22 6.28a.75.75 0 0 1 0-1.06Z" clip-rule="evenodd"/></svg></span>';
|
|
138
|
+
|
|
139
|
+
pagination.innerHTML = prev + '<ol class="flex items-center gap-0.5">' + items + '</ol>' + next;
|
|
140
|
+
pagination.classList.remove('hidden');
|
|
141
|
+
pagination.classList.add('flex');
|
|
142
|
+
}
|
|
143
|
+
|
|
69
144
|
function render(data) {
|
|
145
|
+
loadedData = data;
|
|
70
146
|
var assignment = data.assignment || data;
|
|
71
147
|
var photos = Array.isArray(data.photos) ? data.photos : Array.isArray(data.media) ? data.media : [];
|
|
72
148
|
var name = text(assignment.name, 'Assignment photos');
|
|
73
149
|
var generatedAt = formatDate(data.generatedAt);
|
|
150
|
+
var totalPages = Math.max(1, Math.ceil(photos.length / PAGE_SIZE));
|
|
151
|
+
var currentPage = Math.min(currentPageFromUrl(), totalPages);
|
|
152
|
+
var start = (currentPage - 1) * PAGE_SIZE;
|
|
153
|
+
var visiblePhotos = photos.slice(start, start + PAGE_SIZE);
|
|
74
154
|
|
|
75
155
|
title.textContent = name;
|
|
76
|
-
meta.textContent = photos.length + ' photo' + (photos.length === 1 ? '' : 's') + (generatedAt ? ' updated ' + generatedAt : '');
|
|
156
|
+
meta.textContent = photos.length + ' photo' + (photos.length === 1 ? '' : 's') + (totalPages > 1 ? ' - Page ' + currentPage + ' of ' + totalPages : '') + (generatedAt ? ' updated ' + generatedAt : '');
|
|
157
|
+
refresh.href = window.location.href;
|
|
77
158
|
|
|
78
159
|
if (!photos.length) {
|
|
79
160
|
setStatus('No photos have been published for this assignment yet.');
|
|
80
161
|
return;
|
|
81
162
|
}
|
|
82
163
|
|
|
83
|
-
grid.innerHTML =
|
|
164
|
+
grid.innerHTML = visiblePhotos
|
|
84
165
|
.map(function (item) {
|
|
85
166
|
var url = imageUrl(item);
|
|
86
167
|
var alt = text(item.alt || item.caption || item.originalFilename || item.filename, 'Assignment photo');
|
|
@@ -100,6 +181,7 @@
|
|
|
100
181
|
status.classList.add('hidden');
|
|
101
182
|
grid.classList.remove('hidden');
|
|
102
183
|
grid.classList.add('grid');
|
|
184
|
+
renderPagination(currentPage, totalPages);
|
|
103
185
|
}
|
|
104
186
|
|
|
105
187
|
var assignmentId = assignmentIdFromPath();
|
|
@@ -109,6 +191,20 @@
|
|
|
109
191
|
}
|
|
110
192
|
|
|
111
193
|
refresh.href = window.location.href;
|
|
194
|
+
pagination.addEventListener('click', function (event) {
|
|
195
|
+
var target = event.target;
|
|
196
|
+
if (!(target instanceof Element)) return;
|
|
197
|
+
var anchor = target.closest('a[href]');
|
|
198
|
+
if (!(anchor instanceof HTMLAnchorElement)) return;
|
|
199
|
+
event.preventDefault();
|
|
200
|
+
window.history.pushState({}, '', anchor.getAttribute('href') || window.location.href);
|
|
201
|
+
render(loadedData);
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
window.addEventListener('popstate', function () {
|
|
205
|
+
if (loadedData) render(loadedData);
|
|
206
|
+
});
|
|
207
|
+
|
|
112
208
|
fetch('https://cdn.fifthbell.com/contents/assignments/' + encodeURIComponent(assignmentId) + '.json', {
|
|
113
209
|
cache: 'no-store'
|
|
114
210
|
})
|