mirror of
https://github.com/vector-im/hydrogen-web.git
synced 2025-01-09 11:55:37 +01:00
implement first draft of image lightbox
This commit is contained in:
parent
137264edcb
commit
c9147e6b9a
@ -207,7 +207,9 @@ export class SessionViewModel extends ViewModel {
|
|||||||
this._lightboxViewModel = this.disposeTracked(this._lightboxViewModel);
|
this._lightboxViewModel = this.disposeTracked(this._lightboxViewModel);
|
||||||
}
|
}
|
||||||
if (eventId) {
|
if (eventId) {
|
||||||
this._lightboxViewModel = this.track(new LightboxViewModel(this.childOptions({eventId})));
|
const roomId = this.navigation.path.get("room").value;
|
||||||
|
const room = this._sessionContainer.session.rooms.get(roomId);
|
||||||
|
this._lightboxViewModel = this.track(new LightboxViewModel(this.childOptions({eventId, room})));
|
||||||
}
|
}
|
||||||
this.emitChange("lightboxViewModel");
|
this.emitChange("lightboxViewModel");
|
||||||
}
|
}
|
||||||
|
@ -20,14 +20,78 @@ export class LightboxViewModel extends ViewModel {
|
|||||||
constructor(options) {
|
constructor(options) {
|
||||||
super(options);
|
super(options);
|
||||||
this._eventId = options.eventId;
|
this._eventId = options.eventId;
|
||||||
|
this._unencryptedImageUrl = null;
|
||||||
|
this._decryptedImage = null;
|
||||||
this._closeUrl = this.urlCreator.urlUntilSegment("room");
|
this._closeUrl = this.urlCreator.urlUntilSegment("room");
|
||||||
|
this._eventEntry = null;
|
||||||
|
this._date = null;
|
||||||
|
this._subscribeToEvent(options.room, options.eventId);
|
||||||
}
|
}
|
||||||
|
|
||||||
get eventId() {
|
_subscribeToEvent(room, eventId) {
|
||||||
return this._eventId;
|
const eventObservable = room.observeEvent(eventId);
|
||||||
|
this.track(eventObservable.subscribe(eventEntry => {
|
||||||
|
this._loadEvent(room, eventEntry);
|
||||||
|
}));
|
||||||
|
this._loadEvent(room, eventObservable.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
async _loadEvent(room, eventEntry) {
|
||||||
|
if (!eventEntry) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const {mediaRepository} = room;
|
||||||
|
this._eventEntry = eventEntry;
|
||||||
|
const {content} = this._eventEntry;
|
||||||
|
this._date = this._eventEntry.timestamp ? new Date(this._eventEntry.timestamp) : null;
|
||||||
|
if (content.url) {
|
||||||
|
this._unencryptedImageUrl = mediaRepository.mxcUrl(content.url);
|
||||||
|
this.emitChange("imageUrl");
|
||||||
|
} else if (content.file) {
|
||||||
|
this._decryptedImage = this.track(await mediaRepository.downloadEncryptedFile(content.file));
|
||||||
|
this.emitChange("imageUrl");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get imageWidth() {
|
||||||
|
return this._eventEntry?.content?.info?.w;
|
||||||
|
}
|
||||||
|
|
||||||
|
get imageHeight() {
|
||||||
|
return this._eventEntry?.content?.info?.h;
|
||||||
|
}
|
||||||
|
|
||||||
|
get name() {
|
||||||
|
return this._eventEntry?.content?.body;
|
||||||
|
}
|
||||||
|
|
||||||
|
get sender() {
|
||||||
|
return this._eventEntry?.displayName;
|
||||||
|
}
|
||||||
|
|
||||||
|
get imageUrl() {
|
||||||
|
if (this._decryptedImage) {
|
||||||
|
return this._decryptedImage.url;
|
||||||
|
} else if (this._unencryptedImageUrl) {
|
||||||
|
return this._unencryptedImageUrl;
|
||||||
|
} else {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get date() {
|
||||||
|
return this._date && this._date.toLocaleDateString({}, { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' });
|
||||||
|
}
|
||||||
|
|
||||||
|
get time() {
|
||||||
|
return this._date && this._date.toLocaleTimeString({}, {hour: "numeric", minute: "2-digit"});
|
||||||
}
|
}
|
||||||
|
|
||||||
get closeUrl() {
|
get closeUrl() {
|
||||||
return this._closeUrl;
|
return this._closeUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
close() {
|
||||||
|
this.platform.history.pushUrl(this.closeUrl);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -109,7 +109,6 @@ main {
|
|||||||
use numeric positions because named grid areas
|
use numeric positions because named grid areas
|
||||||
are not present in mobile layout */
|
are not present in mobile layout */
|
||||||
grid-area: 2 / 1 / 3 / 3;
|
grid-area: 2 / 1 / 3 / 3;
|
||||||
background-color: rgba(0,0,0,0.5);
|
|
||||||
/* this should not be necessary, but chrome seems to have a bug when there are scrollbars in other grid items,
|
/* this should not be necessary, but chrome seems to have a bug when there are scrollbars in other grid items,
|
||||||
it seems to put the scroll areas on top of the other grid items unless they have a z-index */
|
it seems to put the scroll areas on top of the other grid items unless they have a z-index */
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
|
@ -632,3 +632,63 @@ button.link {
|
|||||||
color: #03B381;
|
color: #03B381;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.lightbox {
|
||||||
|
background-color: rgba(0,0,0,0.75);
|
||||||
|
display: grid;
|
||||||
|
grid-template:
|
||||||
|
"content close" auto
|
||||||
|
"content details" 1fr /
|
||||||
|
1fr auto;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-aspect-ratio: 1/1) {
|
||||||
|
.lightbox {
|
||||||
|
grid-template:
|
||||||
|
"close" auto
|
||||||
|
"content" 1fr
|
||||||
|
"details" auto /
|
||||||
|
1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lightbox .details {
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.lightbox .picture {
|
||||||
|
grid-area: content;
|
||||||
|
background-size: contain;
|
||||||
|
background-position: center;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lightbox .loading {
|
||||||
|
grid-area: content;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lightbox .close {
|
||||||
|
grid-area: close;
|
||||||
|
margin-left: auto;
|
||||||
|
background-image: url('icons/dismiss.svg');
|
||||||
|
background-position: center;
|
||||||
|
background-size: 16px;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
padding: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lightbox .details {
|
||||||
|
grid-area: details;
|
||||||
|
padding: 12px;
|
||||||
|
font-size: 1.5rem;
|
||||||
|
width: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ export class LoginView extends TemplateView {
|
|||||||
});
|
});
|
||||||
const homeserver = t.input({
|
const homeserver = t.input({
|
||||||
id: "homeserver",
|
id: "homeserver",
|
||||||
type: "text",
|
type: "url",
|
||||||
placeholder: vm.i18n`Your matrix homeserver`,
|
placeholder: vm.i18n`Your matrix homeserver`,
|
||||||
value: vm.defaultHomeServer,
|
value: vm.defaultHomeServer,
|
||||||
disabled
|
disabled
|
||||||
|
@ -15,9 +15,39 @@ limitations under the License.
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {TemplateView} from "../../general/TemplateView.js";
|
import {TemplateView} from "../../general/TemplateView.js";
|
||||||
|
import {spinner} from "../../common.js";
|
||||||
|
|
||||||
export class LightboxView extends TemplateView {
|
export class LightboxView extends TemplateView {
|
||||||
render(t, vm) {
|
render(t, vm) {
|
||||||
return t.div({className: "lightbox"}, [vm.eventId, t.br(), t.a({href: vm.closeUrl}, "close")]);
|
const close = t.a({href: vm.closeUrl, title: vm.i18n`Close`, className: "close"});
|
||||||
|
const image = t.div({
|
||||||
|
role: "img",
|
||||||
|
"aria-label": vm => vm.name,
|
||||||
|
title: vm => vm.name,
|
||||||
|
className: {
|
||||||
|
picture: true,
|
||||||
|
hidden: vm => !vm.imageUrl,
|
||||||
|
},
|
||||||
|
style: vm => `background-image: url('${vm.imageUrl}'); max-width: ${vm.imageWidth}px; max-height: ${vm.imageHeight}px;`
|
||||||
|
});
|
||||||
|
const loading = t.div({
|
||||||
|
className: {
|
||||||
|
loading: true,
|
||||||
|
hidden: vm => !!vm.imageUrl
|
||||||
|
}
|
||||||
|
}, [
|
||||||
|
spinner(t),
|
||||||
|
t.div(vm.i18n`Loading image…`)
|
||||||
|
]);
|
||||||
|
const details = t.div({
|
||||||
|
className: "details"
|
||||||
|
}, [t.strong(vm => vm.name), t.br(), "uploaded by ", t.strong(vm => vm.sender), vm => ` at ${vm.time} on ${vm.date}.`]);
|
||||||
|
return t.div({className: "lightbox", onClick: evt => this.close(evt)}, [image, loading, details, close]);
|
||||||
|
}
|
||||||
|
|
||||||
|
close(evt) {
|
||||||
|
if (evt.target === this.root()) {
|
||||||
|
this.value.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user