Skip to content

Commit 25afb8f

Browse files
Merge pull request #26 from solid-chat/feature/date-navigation
Add date navigation for sharded chat archives
2 parents 2ae197c + b856ac6 commit 25afb8f

File tree

2 files changed

+114
-2
lines changed

2 files changed

+114
-2
lines changed

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/longChatPane.js

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,45 @@ const styles = `
131131
background: rgba(255,255,255,0.3);
132132
}
133133
134+
.date-nav {
135+
display: flex;
136+
align-items: center;
137+
gap: 8px;
138+
margin-right: 8px;
139+
}
140+
141+
.date-nav-btn {
142+
width: 32px;
143+
height: 32px;
144+
border-radius: 50%;
145+
border: none;
146+
background: rgba(255,255,255,0.2);
147+
color: white;
148+
cursor: pointer;
149+
display: flex;
150+
align-items: center;
151+
justify-content: center;
152+
font-size: 14px;
153+
transition: background 0.2s;
154+
}
155+
156+
.date-nav-btn:hover:not(:disabled) {
157+
background: rgba(255,255,255,0.3);
158+
}
159+
160+
.date-nav-btn:disabled {
161+
opacity: 0.4;
162+
cursor: not-allowed;
163+
}
164+
165+
.date-nav-label {
166+
font-size: 13px;
167+
font-weight: 500;
168+
opacity: 0.9;
169+
min-width: 90px;
170+
text-align: center;
171+
}
172+
134173
.messages-container {
135174
flex: 1;
136175
overflow-y: auto;
@@ -857,6 +896,31 @@ function getInitials(name) {
857896
return name.split(' ').map(w => w[0]).join('').slice(0, 2).toUpperCase()
858897
}
859898

899+
// Date navigation helpers for sharded chats
900+
const DATE_SHARD_PATTERN = /\/(\d{4})\/(\d{2})\/(\d{2})\/chat\.(json|jsonld|ttl)$/
901+
902+
function parseDateFromUri(uri) {
903+
const match = uri.match(DATE_SHARD_PATTERN)
904+
if (!match) return null
905+
return new Date(Date.UTC(parseInt(match[1]), parseInt(match[2]) - 1, parseInt(match[3])))
906+
}
907+
908+
function formatDateLabel(date) {
909+
return date.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric', timeZone: 'UTC' })
910+
}
911+
912+
function getAdjacentDateUri(uri, days) {
913+
const match = uri.match(DATE_SHARD_PATTERN)
914+
if (!match) return null
915+
const date = new Date(Date.UTC(parseInt(match[1]), parseInt(match[2]) - 1, parseInt(match[3])))
916+
date.setUTCDate(date.getUTCDate() + days)
917+
const year = date.getUTCFullYear()
918+
const month = String(date.getUTCMonth() + 1).padStart(2, '0')
919+
const day = String(date.getUTCDate()).padStart(2, '0')
920+
const ext = match[4]
921+
return uri.replace(DATE_SHARD_PATTERN, `/${year}/${month}/${day}/chat.${ext}`)
922+
}
923+
860924
// Avatar cache
861925
const avatarCache = new Map()
862926

@@ -1121,6 +1185,54 @@ export const longChatPane = {
11211185

11221186
header.appendChild(titleDiv)
11231187

1188+
// Date navigation (for sharded chats)
1189+
const currentDate = parseDateFromUri(subject.uri)
1190+
if (currentDate) {
1191+
const dateNav = dom.createElement('div')
1192+
dateNav.className = 'date-nav'
1193+
1194+
const prevBtn = dom.createElement('button')
1195+
prevBtn.className = 'date-nav-btn'
1196+
prevBtn.textContent = '←'
1197+
prevBtn.title = 'Previous day'
1198+
prevBtn.onclick = async () => {
1199+
const prevUri = getAdjacentDateUri(subject.uri, -1)
1200+
if (prevUri && window.solidChat?.openChat) {
1201+
window.solidChat.openChat(prevUri)
1202+
} else if (prevUri) {
1203+
window.location.href = `${window.location.pathname}?chat=${encodeURIComponent(prevUri)}`
1204+
}
1205+
}
1206+
dateNav.appendChild(prevBtn)
1207+
1208+
const dateLabel = dom.createElement('span')
1209+
dateLabel.className = 'date-nav-label'
1210+
dateLabel.textContent = formatDateLabel(currentDate)
1211+
dateNav.appendChild(dateLabel)
1212+
1213+
const nextBtn = dom.createElement('button')
1214+
nextBtn.className = 'date-nav-btn'
1215+
nextBtn.textContent = '→'
1216+
nextBtn.title = 'Next day'
1217+
// Disable if viewing today or future
1218+
const today = new Date()
1219+
today.setUTCHours(0, 0, 0, 0)
1220+
if (currentDate >= today) {
1221+
nextBtn.disabled = true
1222+
}
1223+
nextBtn.onclick = async () => {
1224+
const nextUri = getAdjacentDateUri(subject.uri, 1)
1225+
if (nextUri && window.solidChat?.openChat) {
1226+
window.solidChat.openChat(nextUri)
1227+
} else if (nextUri) {
1228+
window.location.href = `${window.location.pathname}?chat=${encodeURIComponent(nextUri)}`
1229+
}
1230+
}
1231+
dateNav.appendChild(nextBtn)
1232+
1233+
header.appendChild(dateNav)
1234+
}
1235+
11241236
// Share button
11251237
const shareBtn = dom.createElement('button')
11261238
shareBtn.className = 'share-btn'

0 commit comments

Comments
 (0)