diff options
Diffstat (limited to 'ui')
| -rw-r--r-- | ui/lib/constants.js | 1 | ||||
| -rw-r--r-- | ui/lib/store.js | 6 | ||||
| -rw-r--r-- | ui/lib/store/channels.svelte.js | 60 | ||||
| -rw-r--r-- | ui/routes/(app)/ch/[channel]/+page.svelte | 12 |
4 files changed, 67 insertions, 12 deletions
diff --git a/ui/lib/constants.js b/ui/lib/constants.js new file mode 100644 index 0000000..a707c4b --- /dev/null +++ b/ui/lib/constants.js @@ -0,0 +1 @@ +export const STORE_KEY_CHANNELS_DATA = 'pilcrow:channelsData'; diff --git a/ui/lib/store.js b/ui/lib/store.js index 47ebbc2..f408c0c 100644 --- a/ui/lib/store.js +++ b/ui/lib/store.js @@ -1,9 +1,13 @@ import { writable } from 'svelte/store'; +import { browser } from '$app/environment'; import { Channels } from '$lib/store/channels.svelte.js'; import { Messages } from '$lib/store/messages.svelte.js'; import { Logins } from '$lib/store/logins'; +// Get channelsList content from the local storage +const channelsData = (browser && JSON.parse(localStorage.getItem('pilcrow:channelsData'))) || {}; + export const currentUser = writable(null); export const logins = writable(new Logins()); -export const channelsList = writable(new Channels()); +export const channelsList = writable(new Channels({ channelsData })); export const messages = writable(new Messages()); diff --git a/ui/lib/store/channels.svelte.js b/ui/lib/store/channels.svelte.js index c82f9aa..49cc31c 100644 --- a/ui/lib/store/channels.svelte.js +++ b/ui/lib/store/channels.svelte.js @@ -1,4 +1,5 @@ import { DateTime } from 'luxon'; +import { STORE_KEY_CHANNELS_DATA } from '$lib/constants'; const EPOCH_STRING = '1970-01-01T00:00:00Z'; // For reasons unclear to me, a straight up class definition with a constructor @@ -10,24 +11,79 @@ const EPOCH_STRING = '1970-01-01T00:00:00Z'; // Emphasis on "simple object". // --Kit function makeChannelObject({ id, name, draft = '', lastReadAt = null, scrollPosition = null }) { + let lastReadAtParsed; + if (Boolean(lastReadAt)) { + if (typeof lastReadAt === "string") { + lastReadAtParsed = DateTime.fromISO(lastReadAt); + } else { + lastReadAtParsed = lastReadAt; + } + } else { + lastReadAtParsed = DateTime.fromISO(EPOCH_STRING); + } return { id, name, - lastReadAt: lastReadAt || DateTime.fromISO(EPOCH_STRING), + lastReadAt: lastReadAtParsed, draft, scrollPosition }; } +function mergeLocalData(remoteData, currentData) { + let currentDataObj = currentData.reduce( + (acc, cur) => { + acc[cur.id] = cur; + return acc; + }, + {} + ); + const ret = remoteData.map( + (ch) => { + const newCh = makeChannelObject(ch); + if (Boolean(currentDataObj[ch.id])) { + newCh.lastReadAt = currentDataObj[ch.id].lastReadAt; + } + return newCh; + } + ); + return ret; +} + export class Channels { channels = $state([]); + constructor({ channelsData }) { + this.channels = channelsData.map(makeChannelObject); + // On channel edits (inc 'last read' ones), write out to localstorage? + } + + writeOutToLocalStorage() { + localStorage.setItem( + STORE_KEY_CHANNELS_DATA, + JSON.stringify(this.channels) + ); + } + + updateLastReadAt(channelId, at) { + const channelObject = this.getChannel(channelId); + // Do it this way, rather than with Math.max tricks, to avoid assignment + // when we don't need it, to minimize reactive changes: + if (at > channelObject.lastReadAt) { + channelObject.lastReadAt = at; + this.writeOutToLocalStorage(); + } + } + getChannel(channelId) { return this.channels.filter((ch) => ch.id === channelId)[0] || null; } setChannels(channels) { - this.channels = channels.map(makeChannelObject); + // This gets called, among other times, when the page is first loaded, with + // server-sent data from the `boot` endpoint. That needs to be merged with + // locally stored data! + this.channels = mergeLocalData(channels, this.channels); this.sort(); return this; } diff --git a/ui/routes/(app)/ch/[channel]/+page.svelte b/ui/routes/(app)/ch/[channel]/+page.svelte index dbdb507..d64a8c9 100644 --- a/ui/routes/(app)/ch/[channel]/+page.svelte +++ b/ui/routes/(app)/ch/[channel]/+page.svelte @@ -33,16 +33,10 @@ } function setLastRead() { - const channelObject = $channelsList.getChannel(channel); const lastInView = getLastVisibleMessage(); - if (!channelObject || !lastInView) { - return; - } - const at = DateTime.fromISO(lastInView.dataset.at); - // Do it this way, rather than with Math.max tricks, to avoid assignment - // when we don't need it, to minimize reactive changes: - if (at > channelObject.lastReadAt) { - channelObject.lastReadAt = at; + if (lastInView) { + const at = DateTime.fromISO(lastInView.dataset.at); + $channelsList.updateLastReadAt(channel, at); } } |
