Make the archive responsive (#53)

This also needs a release of `@mlm/hydrogen-view-sdk` with our latest scratch changes in https://github.com/vector-im/hydrogen-web/pull/653 but we can make the dependency update later.
This commit is contained in:
Eric Eastwood 2022-08-30 18:47:03 -05:00 committed by GitHub
parent b45c31a597
commit eb5dc23d5d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 137 additions and 8 deletions

View File

@ -29,9 +29,50 @@ body {
min-width: 0; min-width: 0;
} }
/* No need to open the right-panel when it's always visible at desktop widths */
.room-header-change-dates-button {
display: none;
color: var(--icon-color--darker-20);
}
/* No need to close the right-panel when it's always visible at desktop widths */
.RightPanelView_buttons .close {
display: none;
}
@media screen and (max-width: 800px) {
/* Only the middle needs to be visible mobile by default */
.ArchiveView {
grid-template:
'status' auto
'middle' 1fr /
1fr;
}
/* Which also means hiding the right-panel by default on mobile */
.ArchiveView:not(.right-shown) .RightPanelView {
display: none;
}
/* When the user opens the right-panel, show it */
.ArchiveView.right-shown {
grid-template:
'status' auto
'right' 1fr /
1fr;
}
.ArchiveView.right-shown .middle {
display: none;
}
/* And show the button to open the right-panel on mobile */
.room-header-change-dates-button {
display: block;
}
/* And show the button to close the right-panel on mobile */
.RightPanelView_buttons .close {
display: block;
}
}
.CalendarView { .CalendarView {
max-width: 280px;
font: 100% system-ui;
} }
.CalendarView_header { .CalendarView_header {
@ -132,7 +173,8 @@ body {
.CalendarView_dayLink { .CalendarView_dayLink {
display: inline-block; display: inline-block;
width: 100%; width: 100%;
padding: 2px 5px; padding-top: 18%;
padding-bottom: 18%;
text-decoration: none; text-decoration: none;
} }
@ -154,7 +196,6 @@ body {
opacity: 0.5; opacity: 0.5;
} }
/* Error pages */ /* Error pages */
.heading-sub-detail { .heading-sub-detail {
@ -162,7 +203,6 @@ body {
} }
.tracing-span-list { .tracing-span-list {
} }
.tracing-span-list-item { .tracing-span-list-item {
@ -170,7 +210,6 @@ body {
} }
.tracing-span-item-http-details { .tracing-span-item-http-details {
} }
.tracing-span-item-sub-details { .tracing-span-item-sub-details {

View File

@ -209,6 +209,7 @@ function installRoutes(app) {
<!doctype html> <!doctype html>
<html lang="en"> <html lang="en">
<head> <head>
<meta name="viewport" content="width=device-width, initial-scale=1">
${sanitizeHtml(`<title>${roomData.name} - Matrix Public Archive</title>`)} ${sanitizeHtml(`<title>${roomData.name} - Matrix Public Archive</title>`)}
<link href="${hydrogenStylesUrl}" rel="stylesheet"> <link href="${hydrogenStylesUrl}" rel="stylesheet">
<link href="${stylesUrl}" rel="stylesheet"> <link href="${stylesUrl}" rel="stylesheet">

View File

@ -55,6 +55,7 @@ async function timeoutMiddleware(req, res, next) {
<!doctype html> <!doctype html>
<html lang="en"> <html lang="en">
<head> <head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Server timeout - Matrix Public Archive</title> <title>Server timeout - Matrix Public Archive</title>
<link href="${hydrogenStylesUrl}" rel="stylesheet"> <link href="${hydrogenStylesUrl}" rel="stylesheet">
<link href="${stylesUrl}" rel="stylesheet"> <link href="${stylesUrl}" rel="stylesheet">

View File

@ -234,6 +234,13 @@ async function mountHydrogen() {
navigation, navigation,
}); });
roomViewModel.openRightPanel = function () {
let path = this.navigation.path.until('room');
path = path.with(this.navigation.segment('right-panel', true));
path = path.with(this.navigation.segment('change-dates', true));
this.navigation.applyPath(path);
};
// FIXME: We shouldn't have to dive into the internal fields to make this work // FIXME: We shouldn't have to dive into the internal fields to make this work
roomViewModel._timelineVM = timelineViewModel; roomViewModel._timelineVM = timelineViewModel;
roomViewModel._composerVM = { roomViewModel._composerVM = {
@ -292,6 +299,7 @@ async function mountHydrogen() {
class ArchiveViewModel extends ViewModel { class ArchiveViewModel extends ViewModel {
roomViewModel = roomViewModel; roomViewModel = roomViewModel;
rightPanelModel = { rightPanelModel = {
navigation,
activeViewModel: { activeViewModel: {
type: 'custom', type: 'custom',
customView: RightPanelContentView, customView: RightPanelContentView,
@ -302,15 +310,27 @@ async function mountHydrogen() {
calendarDate: fromDate, calendarDate: fromDate,
}), }),
}, },
closePanel() {
const path = this.navigation.path.until('room');
this.navigation.applyPath(path);
},
}; };
get shouldShowRightPanel() {
return this._shouldShowRightPanel;
}
constructor(options) { constructor(options) {
super(options); super(options);
this.#setupNavigation(); this.#setupNavigation();
this._updateRightPanel();
} }
#setupNavigation() { #setupNavigation() {
const rightpanel = this.navigation.observe('right-panel');
this.track(rightpanel.subscribe(() => this._updateRightPanel()));
setupLightboxNavigation(this, 'lightboxViewModel', (eventId) => { setupLightboxNavigation(this, 'lightboxViewModel', (eventId) => {
return { return {
room, room,
@ -318,6 +338,11 @@ async function mountHydrogen() {
}; };
}); });
} }
_updateRightPanel() {
this._shouldShowRightPanel = !!this.navigation.path.get('right-panel')?.value;
this.emitChange('shouldShowRightPanel');
}
} }
const archiveViewModel = new ArchiveViewModel({ const archiveViewModel = new ArchiveViewModel({

View File

@ -2,22 +2,70 @@
const { const {
TemplateView, TemplateView,
AvatarView,
RoomView, RoomView,
RightPanelView, RightPanelView,
LightboxView, LightboxView,
viewClassForTile, viewClassForTile,
} = require('hydrogen-view-sdk'); } = require('hydrogen-view-sdk');
class RoomHeaderView extends TemplateView {
render(t, vm) {
return t.div({ className: 'RoomHeader middle-header' }, [
t.view(new AvatarView(vm, 32)),
t.div({ className: 'room-description' }, [t.h2((vm) => vm.name)]),
t.button(
{
className: 'button-utility room-header-change-dates-button',
'aria-label': vm.i18n`Change dates`,
onClick: (/*evt*/) => {
vm.openRightPanel();
},
},
[
// Calendar icon (via `calendar2-date` from Bootstrap)
t.svg(
{
xmlns: 'http://www.w3.org/2000/svg',
width: '16',
height: '16',
viewBox: '0 0 16 16',
fill: 'currentColor',
style: 'vertical-align: middle;',
},
[
t.path({
d: 'M6.445 12.688V7.354h-.633A12.6 12.6 0 0 0 4.5 8.16v.695c.375-.257.969-.62 1.258-.777h.012v4.61h.675zm1.188-1.305c.047.64.594 1.406 1.703 1.406 1.258 0 2-1.066 2-2.871 0-1.934-.781-2.668-1.953-2.668-.926 0-1.797.672-1.797 1.809 0 1.16.824 1.77 1.676 1.77.746 0 1.23-.376 1.383-.79h.027c-.004 1.316-.461 2.164-1.305 2.164-.664 0-1.008-.45-1.05-.82h-.684zm2.953-2.317c0 .696-.559 1.18-1.184 1.18-.601 0-1.144-.383-1.144-1.2 0-.823.582-1.21 1.168-1.21.633 0 1.16.398 1.16 1.23z',
}),
t.path({
d: 'M3.5 0a.5.5 0 0 1 .5.5V1h8V.5a.5.5 0 0 1 1 0V1h1a2 2 0 0 1 2 2v11a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V3a2 2 0 0 1 2-2h1V.5a.5.5 0 0 1 .5-.5zM2 2a1 1 0 0 0-1 1v11a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1H2z',
}),
t.path({
d: 'M2.5 4a.5.5 0 0 1 .5-.5h10a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-.5.5H3a.5.5 0 0 1-.5-.5V4z',
}),
]
),
]
),
]);
}
}
class ArchiveView extends TemplateView { class ArchiveView extends TemplateView {
render(t, vm) { render(t, vm) {
return t.div( return t.div(
{ {
className: { className: {
ArchiveView: true, ArchiveView: true,
'right-shown': (vm) => vm.shouldShowRightPanel,
}, },
}, },
[ [
t.view(new RoomView(vm.roomViewModel, viewClassForTile)), t.view(
new RoomView(vm.roomViewModel, viewClassForTile, {
RoomHeaderView,
})
),
t.view(new RightPanelView(vm.rightPanelModel)), t.view(new RightPanelView(vm.rightPanelModel)),
t.mapView( t.mapView(
(vm) => vm.lightboxViewModel, (vm) => vm.lightboxViewModel,

View File

@ -66,6 +66,7 @@ class CalendarView extends TemplateView {
month: 'long', month: 'long',
timeZone: 'UTC', timeZone: 'UTC',
}), }),
// Dropdown arrow
t.svg( t.svg(
{ {
xmlns: 'http://www.w3.org/2000/svg', xmlns: 'http://www.w3.org/2000/svg',

View File

@ -27,10 +27,24 @@ class ArchiveHistory extends History {
// downstream call of `urlRouter.attach()` which we do when bootstraping // downstream call of `urlRouter.attach()` which we do when bootstraping
// everything. // everything.
if (window.history) { if (window.history) {
super.replaceUrlSilently(url); let replacingUrl = url;
// This is a way to make sure the hash gets cleared out
if (url === '') {
replacingUrl = window.location.pathname;
}
super.replaceUrlSilently(replacingUrl);
} }
} }
pushUrlSilently(url) {
let replacingUrl = url;
// This is a way to make sure the hash gets cleared out
if (url === '') {
replacingUrl = window.location.pathname;
}
super.pushUrlSilently(replacingUrl);
}
// Make the URLs we use in the UI of the app relative to the room: // Make the URLs we use in the UI of the app relative to the room:
// Before: #/session/123/room/!HBehERstyQBxyJDLfR:my.synapse.server/lightbox/$17cgP6YBP9ny9xuU1vBmpOYFhRG4zpOe9SOgWi2Wxsk // Before: #/session/123/room/!HBehERstyQBxyJDLfR:my.synapse.server/lightbox/$17cgP6YBP9ny9xuU1vBmpOYFhRG4zpOe9SOgWi2Wxsk
// After: #/lightbox/$17cgP6YBP9ny9xuU1vBmpOYFhRG4zpOe9SOgWi2Wxsk // After: #/lightbox/$17cgP6YBP9ny9xuU1vBmpOYFhRG4zpOe9SOgWi2Wxsk