Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create a fullscreen toggle element #440

Merged
merged 8 commits into from
Oct 13, 2023
72 changes: 72 additions & 0 deletions src/renderer/src/stories/FullScreenToggle.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { LitElement, css, html } from "lit";

import fullScreenIcon from './assets/fullscreen.svg?raw'
import fullScreenExitIcon from './assets/fullscreen_exit.svg?raw'

import { unsafeHTML } from "lit/directives/unsafe-html.js";

type FullScreenToggleProps = {
target: HTMLElement | (() => HTMLElement);
}

export class FullScreenToggle extends LitElement {
static get styles() {
return css`
:host {
display: flex;
position: absolute;
top: 10px;
right: 10px;
padding: 10px;
color: white;
background-color: gainsboro;
border: 1px solid gray;
border-radius: 10px;
cursor: pointer;
box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.3);
z-index: 1000;
opacity: 0.5;
transition: opacity 0.5s;
}
:host(:hover) {
opacity: 1;
}
`;
}

static get properties() {
return {
icon: { type: String },
};
}

declare icon: string;
declare target: FullScreenToggleProps['target'];

constructor({ target }: FullScreenToggleProps) {

super();
this.target = target;
this.icon = fullScreenIcon

const fullscreenchanged = () => this.icon = document.fullscreenElement ? fullScreenExitIcon : fullScreenIcon

this.addEventListener('click', () => {
const target = (typeof this.target === 'function' ? this.target() : this.target)

target.addEventListener("fullscreenchange", fullscreenchanged);

const fullScreenEl = document.fullscreenElement
if (!fullScreenEl) target.requestFullscreen()
else document.exitFullscreen()

})
}

render() {
return html`${unsafeHTML(this.icon)}`;
}
}

customElements.get("fullscreen-toggle") || customElements.define("fullscreen-toggle", FullScreenToggle);
6 changes: 3 additions & 3 deletions src/renderer/src/stories/List.ts
Original file line number Diff line number Diff line change
Expand Up @@ -240,10 +240,10 @@ export class List extends LitElement {

const { items, emptyMessage} = this

return items.length || !emptyMessage ? html`
return html`
<ol style=${styleMap(this.listStyles)}>
${items.map(this.#renderListItem)}
</ol>` : html`<div id="empty">${emptyMessage}</div>`
${(items.length || !emptyMessage) ? items.map(this.#renderListItem) : html`<div id="empty">${emptyMessage}</div>`}
</ol>`
}
}

Expand Down
1 change: 1 addition & 0 deletions src/renderer/src/stories/Modal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ export class Modal extends LitElement {
/* Modal Body */
.modal-body {
position: relative;
overflow-y: auto;
width: 100%;
flex-grow: 1;
Expand Down
1 change: 1 addition & 0 deletions src/renderer/src/stories/assets/fullscreen.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions src/renderer/src/stories/assets/fullscreen_exit.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
125 changes: 72 additions & 53 deletions src/renderer/src/stories/preview/NWBFilePreview.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { run } from "../pages/guided-mode/options/utils";
import { until } from "lit/directives/until.js";
import { InstanceManager } from "../InstanceManager";
import { path } from "../../electron";
import { FullScreenToggle } from "../FullScreenToggle";

export function getSharedPath(array) {
array = array.map((str) => str.replace(/\\/g, "/")); // Convert to Mac-style path
Expand Down Expand Up @@ -55,7 +56,7 @@ class NWBPreviewInstance extends LitElement {
const isOnline = navigator.onLine;

return isOnline
? new Neurosift({ url: getURLFromFilePath(this.file, this.project) })
? new Neurosift({ url: getURLFromFilePath(this.file, this.project), fullscreen: false })
: until(
(async () => {
const htmlRep = await run("html", { nwbfile_path: this.file }, { swal: false });
Expand All @@ -71,11 +72,27 @@ customElements.get("nwb-preview-instance") || customElements.define("nwb-preview
export class NWBFilePreview extends LitElement {
static get styles() {
return css`
:host {
display: block;
width: 100%;
height: 100%;
background: white;
position: relative;
}
iframe {
width: 100%;
height: 100%;
border: 0;
}
#inspect {
display: flex;
flex-direction: column;
border-left: 1px solid gray;
box-shadow: -5px 0 5px -5px rgba(0, 0, 0, 0.5);
z-index: 1;
}
`;
}

Expand Down Expand Up @@ -105,58 +122,60 @@ export class NWBFilePreview extends LitElement {

const onlyFirstFile = fileArr.length <= 1;

return html`<div style="display: flex; height: 100%;">
<div style="flex-grow: 1;">
${(() => {
if (onlyFirstFile) return new NWBPreviewInstance(fileArr[0].info, this.project);
else {
const _instances = fileArr.map(this.createInstance);
const instances = _instances.reduce((acc, { subject, session, display }) => {
if (!acc[`sub-${subject}`]) acc[`sub-${subject}`] = {};
acc[`sub-${subject}`][`ses-${session}`] = display;
return acc;
}, {});
return new InstanceManager({ instances });
}
})()}
</div>
${this.inspect
? html`<div style="padding-left: 20px; display: flex; flex-direction: column;">
<h3 style="padding: 10px; margin: 0; background: black; color: white;">Inspector Report</h3>
${until(
(async () => {
const opts = {}; // NOTE: Currently options are handled on the Python end until exposed to the user
const title = "Inspecting your file";
const items = onlyFirstFile
? removeFilePaths(
await run(
"inspect_file",
{ nwbfile_path: fileArr[0].info.file, ...opts },
{ title }
)
) // Inspect the first file
: await (async () =>
truncateFilePaths(
await run("inspect_folder", { path, ...opts }, { title: title + "s" }),
getSharedPath(fileArr.map((o) => o.info.file))
))();
const list = new InspectorList({
items: items,
listStyles: { maxWidth: "350px" },
});
list.style.padding = "10px";
return list;
})(),
html`<small style="padding: 10px 25px;">Loading inspector report...</small>`
)}
</div>`
: ""}
</div>`;
return html` ${new FullScreenToggle({ target: this })}
<div style="display: flex; height: 100%;">
<div style="flex-grow: 1;">
${(() => {
if (onlyFirstFile) return new NWBPreviewInstance(fileArr[0].info, this.project);
else {
const _instances = fileArr.map(this.createInstance);
const instances = _instances.reduce((acc, { subject, session, display }) => {
if (!acc[`sub-${subject}`]) acc[`sub-${subject}`] = {};
acc[`sub-${subject}`][`ses-${session}`] = display;
return acc;
}, {});
return new InstanceManager({ instances });
}
})()}
</div>
${this.inspect
? html`<div id="inspect">
<h3 style="padding: 10px; margin: 0; background: black; color: white;">Inspector Report</h3>
${until(
(async () => {
const opts = {}; // NOTE: Currently options are handled on the Python end until exposed to the user
const title = "Inspecting your file";
const items = onlyFirstFile
? removeFilePaths(
await run(
"inspect_file",
{ nwbfile_path: fileArr[0].info.file, ...opts },
{ title }
)
) // Inspect the first file
: await (async () =>
truncateFilePaths(
await run("inspect_folder", { path, ...opts }, { title: title + "s" }),
getSharedPath(fileArr.map((o) => o.info.file))
))();
const list = new InspectorList({
items: items,
listStyles: { minWidth: "300px", maxWidth: "350px" },
emptyMessage: "No issues found.",
});
list.style.padding = "10px";
return list;
})(),
html`<small style="padding: 10px 25px;">Loading inspector report...</small>`
)}
</div>`
: ""}
</div>`;
}
}

Expand Down
28 changes: 23 additions & 5 deletions src/renderer/src/stories/preview/Neurosift.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { LitElement, css, html } from "lit";
import { baseUrl } from "../../globals";

import { Loader } from "../Loader";
import { FullScreenToggle } from "../FullScreenToggle";

export function getURLFromFilePath(file, projectName) {
const regexp = new RegExp(`.+(${projectName}.+)`);
Expand All @@ -12,6 +13,7 @@ export class Neurosift extends LitElement {
static get styles() {
return css`
:host {
background: white;
width: 100%;
height: 100%;
display: grid;
Expand All @@ -21,7 +23,8 @@ export class Neurosift extends LitElement {
--loader-color: hsl(200, 80%, 50%);
}
:host > * {
iframe,
.loader-container {
width: 100%;
height: 100%;
}
Expand All @@ -35,6 +38,19 @@ export class Neurosift extends LitElement {
left: 0;
}
.fullscreen-toggle {
display: flex;
position: absolute;
top: 10px;
right: 10px;
padding: 10px;
color: white;
background-color: gainsboro;
border: 1px solid gray;
border-radius: 10px;
cursor: pointer;
}
span {
font-size: 14px;
}
Expand All @@ -55,21 +71,23 @@ export class Neurosift extends LitElement {
};
}

constructor({ url } = {}) {
constructor({ url, fullscreen = true } = {}) {
super();
this.url = url;
this.fullscreen = fullscreen;
}

render() {
return this.url
? html` <div class="loader-container">
${new Loader({ message: `Loading Neurosift view...<br/><small>${this.url}</small>` })}
</div>
${this.fullscreen ? new FullScreenToggle({ target: this }) : ""}
<iframe
class="iframe-placeholder"
src="https://flatironinstitute.github.io/neurosift/?p=/nwb&url=${this.url}"
@load=${function (ev) {
ev.target.previousElementSibling.remove();
@load=${function () {
const loader = this.shadowRoot.querySelector(".loader-container");
loader.remove();
}}
></iframe>`
: ``;
Expand Down
Loading