diff --git a/public/styles/styles.css b/public/styles/styles.css index 07f1f8b..751b6a1 100644 --- a/public/styles/styles.css +++ b/public/styles/styles.css @@ -59,3 +59,10 @@ .CalendarView_day { padding: 2px; } + +.CalendarView_dayLink { +} + +.CalendarView_dayLink_active { + background-color: #f00; +} diff --git a/server/render-hydrogen-to-string.js b/server/render-hydrogen-to-string.js index 9b9c4c6..5a47c3d 100644 --- a/server/render-hydrogen-to-string.js +++ b/server/render-hydrogen-to-string.js @@ -9,7 +9,8 @@ const { parseHTML } = require('linkedom'); const config = require('../config.json'); -async function renderToString(roomData, events, stateEventMap) { +async function renderToString({ fromTimestamp, roomData, events, stateEventMap }) { + assert(fromTimestamp); assert(roomData); assert(events); assert(stateEventMap); @@ -32,6 +33,7 @@ async function renderToString(roomData, events, stateEventMap) { // Define this for the SSR context dom.window.matrixPublicArchiveContext = { + fromTimestamp, roomData, events, stateEventMap, diff --git a/server/routes/install-routes.js b/server/routes/install-routes.js index b1189c4..38caaa2 100644 --- a/server/routes/install-routes.js +++ b/server/routes/install-routes.js @@ -117,7 +117,12 @@ function installRoutes(app) { fetchEventsForTimestamp(roomIdOrAlias, fromTimestamp), ]); - const hydrogenHtmlOutput = await renderHydrogenToString(roomData, events, stateEventMap); + const hydrogenHtmlOutput = await renderHydrogenToString({ + fromTimestamp, + roomData, + events, + stateEventMap, + }); const hydrogenStylesUrl = urlJoin(basePath, 'hydrogen-styles.css'); const stylesUrl = urlJoin(basePath, 'styles.css'); diff --git a/shared/CalendarView.js b/shared/CalendarView.js index 7a6dd65..8c81c95 100644 --- a/shared/CalendarView.js +++ b/shared/CalendarView.js @@ -2,6 +2,14 @@ const { TemplateView } = require('hydrogen-view-sdk'); +function sameDay(date1, date2) { + return ( + date1.getFullYear() === date2.getFullYear() && + date1.getMonth() === date2.getMonth() && + date1.getDate() === date2.getDate() + ); +} + // Month in JavaScript is 0-indexed (January is 0, February is 1, etc), // but by using 0 as the day it will give us the last day of the prior // month. @@ -46,7 +54,7 @@ class CalendarView extends TemplateView { ['\u276E'] ), t.map( - (vm) => vm.date, + (vm) => vm.calendarDate, (date, t) => { return t.h4({ className: { CalendarView_heading_text: true } }, [ date.toLocaleString('default', { year: 'numeric', month: 'long' }), @@ -62,8 +70,8 @@ class CalendarView extends TemplateView { ), ]), t.map( - (vm) => vm.date, - (date, t) => { + (vm) => vm.calendarDate, + (calendarDate, t) => { return t.ol( { className: { CalendarView_calendar: true } }, [].concat( @@ -71,10 +79,16 @@ class CalendarView extends TemplateView { return t.li({ className: { CalendarView_dayName: true } }, [DAYS_OF_WEEK[dayKey]]); }), (() => { + const todayTs = Date.now(); + let dayNodes = []; - for (let i = 0; i < numDaysInMonthForDate(date); i++) { - const dayNumberDate = new Date(date); + for (let i = 0; i < numDaysInMonthForDate(calendarDate); i++) { + const dayNumberDate = new Date(calendarDate); dayNumberDate.setDate(i); + const isDayInFuture = dayNumberDate.getTime() - todayTs > 0; + + // The current day displayed in the archive + const isActive = sameDay(dayNumberDate, vm.activeDate); // day number from 0 (monday) to 6 (sunday) const dayNumber = dayNumberDate.getDay(); @@ -89,7 +103,19 @@ class CalendarView extends TemplateView { className: { CalendarView_day: true }, style: i === 0 ? `grid-column-start: ${gridColumnStart};` : null, }, - [t.a({ href: vm.linkForDate(dayNumberDate) }, [String(i + 1)])] + [ + t.a( + { + className: { + CalendarView_dayLink: true, + CalendarView_dayLink_active: isActive, + }, + // Disable navigation to future days + href: isDayInFuture ? null : vm.linkForDate(dayNumberDate), + }, + [String(i + 1)] + ), + ] ) ); } diff --git a/shared/RightPanelContentView.js b/shared/RightPanelContentView.js index 9e9c2a3..e9097f9 100644 --- a/shared/RightPanelContentView.js +++ b/shared/RightPanelContentView.js @@ -16,7 +16,7 @@ class RightPanelContentView extends TemplateView { t.div('test'), t.input({ type: 'date', - value: vm.calendarViewModel.date.toISOString().split('T')[0], + value: vm.calendarViewModel.activeDate.toISOString().split('T')[0], }), t.view(new CalendarView(vm.calendarViewModel)), ] diff --git a/shared/hydrogen-vm-render-script.js b/shared/hydrogen-vm-render-script.js index 58e862f..91d897a 100644 --- a/shared/hydrogen-vm-render-script.js +++ b/shared/hydrogen-vm-render-script.js @@ -6,6 +6,7 @@ const { MediaRepository, createNavigation, createRouter, + Segment, TilesCollection, FragmentIdComparer, @@ -24,6 +25,8 @@ const urlJoin = require('url-join'); const ArchiveView = require('matrix-public-archive-shared/ArchiveView'); const RightPanelContentView = require('matrix-public-archive-shared/RightPanelContentView'); +const fromTimestamp = window.matrixPublicArchiveContext.fromTimestamp; +assert(fromTimestamp); const roomData = window.matrixPublicArchiveContext.roomData; assert(roomData); const events = window.matrixPublicArchiveContext.events; @@ -60,6 +63,7 @@ function makeEventEntryFromEventJson(eventJson, memberEvent) { return eventEntry; } +// eslint-disable-next-line max-statements async function mountHydrogen() { const app = document.querySelector('#app'); @@ -88,21 +92,35 @@ async function mountHydrogen() { homeserver: config.matrixServerUrl, }); - // const urlCreator = { + // const urlRouter = { // urlUntilSegment: () => { // return 'todo'; // }, - // urlForSegments: () => { + // urlForSegments: (segments) => { + // const isLightBox = segments.find((segment) => { + // return segment.type === 'lightbox'; + // console.log('segment', segment); + // }); + + // if (isLightBox) { + // return '#'; + // } + // return 'todo'; // }, // }; // const navigation = { - // segment: () => { - // return 'todo'; + // segment: (type, value) => { + // return new Segment(type, value); // }, // }; + const lightbox = navigation.observe('lightbox'); + lightbox.subscribe((eventId) => { + this._updateLightbox(eventId); + }); + const room = { name: roomData.name, id: roomData.id, @@ -194,12 +212,17 @@ async function mountHydrogen() { class CalendarViewModel extends ViewModel { constructor(options) { super(options); - const { date } = options; - this._date = date; + const { activeDate, calendarDate } = options; + this._activeDate = activeDate; + this._calendarDate = calendarDate; } - get date() { - return this._date; + get activeDate() { + return this._activeDate; + } + + get calendarDate() { + return this._calendarDate; } linkForDate(date) { @@ -211,27 +234,33 @@ async function mountHydrogen() { } prevMonth() { - const prevMonthDate = new Date(this._date); + const prevMonthDate = new Date(this._calendarDate); prevMonthDate.setMonth(this._date.getMonth() - 1); - this._date = prevMonthDate; + this._calendarDate = prevMonthDate; this.emitChange('date'); } nextMonth() { - const nextMonthDate = new Date(this._date); + const nextMonthDate = new Date(this._calendarDate); nextMonthDate.setMonth(this._date.getMonth() + 1); - this._date = nextMonthDate; + this._calendarDate = nextMonthDate; this.emitChange('date'); } } + const fromDate = new Date(fromTimestamp); const archiveViewModel = { roomViewModel, rightPanelModel: { activeViewModel: { type: 'custom', customView: RightPanelContentView, - calendarViewModel: new CalendarViewModel({ date: new Date() }), + calendarViewModel: new CalendarViewModel({ + // The day being shown in the archive + activeDate: fromDate, + // The month displayed in the calendar + calendarDate: fromDate, + }), }, }, };