{% extends layout|default('base.html', true) %} {% block style %} {% endblock %} {% block content %} {% if data.datasource %}
{# The one place the viewer's ground colour is not the app's. A transmitted-light image IS its white background, and the dark shell behind it reads as a shadow the scanner never recorded. #}
{# The calibration pencil. Parked here and moved into OpenSeadragon's container by views/scaleCalibration.js, which then keeps it beside the scale bar -- see that file. #} {% include "_scale_calibration_float.html" %}
{# What takes the centre spinner down. The spinner is in this page's own markup and visible from first paint, so this has to be loaded before main.js builds the viewer and calls watch() on it -- deferred scripts run in document order, which is the whole reason it sits above rather than in base.html with the other services. Viewer-only: no other page has the element. #} {# Grab/grabbing on the OSD canvas. Deferred and unconditional within this branch: it installs three document-level listeners that cost nothing until a press lands inside a `.openseadragon-canvas`, which only this page has -- either viewer's. #} {# Before main.js and deferred like it, so it is defined by the time init() sees a pending mask job. Loaded here rather than in base.html because the pending state belongs to a viewer looking at the project whose mask is converting -- every other page would carry a listener with nothing to listen for. #} {# Brightfield display adjustments. Deferred like main.js and loaded unconditionally: it does nothing at all when its sliders are absent, and gating the tag on image_kind would put a second thing in this page that has to agree with the staged markup above. It runs after main.js has built the base image layer's card, which is where those sliders will be by then. #} {# Here rather than base.html for the same reason: the only things that open it are the channel list and a registered layer's channel panel, and both are the viewer's. Only has to exist by the time the user clicks one of those upload buttons, so deferred is ample. #} {# What the last sample arranged, on its way into this one. BEFORE main.js and deferred like it, so the snapshot is on hand by the time init() builds the channel slots -- the sidebar reads it while deciding which channels to turn on, which is the earliest any of it is wanted. Viewer-only: nothing else has an arrangement to carry. #} {# Previous / Next for a sample that belongs to a dataset. Deliberately independent of main.js: a sample whose image will not open has no viewer at all, and this is the way out of it. It mounts off its own fetch and asks the viewer for nothing. #} {# Why the canvas is empty, when it is. Before main.js, which calls it from the boot path the moment a load comes back without an image. #} {% else %} {# The home page when nothing is registered yet. One vertical run of four things, in the order they are needed: which machine, which image, the typed way in, and the way out to the full import. The one gesture -- pick an image, land in the viewer -- is what this page is for, and it is the page's own control rather than a button that opens the import dialog: a modal covering an otherwise empty page is a step, not a shortcut. What it is NOT any more is a second importer. The Load button POSTs to `/import/sample`, the same route the dialog submits to, so a Xenium run dropped here brings its transcripts and its table with it instead of being refused for not being one image. See views/quickViewLanding.js. The footer is the way to everything that needs a decision -- several samples in one folder, a name, a dataset, a question answered. That is the dialog, and it is one link rather than the page's headline act. #}

Plexora

{# Which machine the image is on, asked ONCE for the whole page. Everywhere else this switch sits inside the row of the one field it governs; here it governs two controls -- the File/Folder pair and the path box -- so it stands above them both, and asking twice on a page whose whole job is one image is what that avoids. services/dataLocation.js renders the [L|R] chip and the place button into `#quick_view_where_control`. The label and the caption beside it are this page's own: two bare letters standing alone explain nothing without a word next to them, and on a form the word they do not need is supplied by the box they sit against. #}
Image location
{# Local only. On Remote the switch's own place button stands here instead and names the machine -- and unlike this caption it is clickable, which is how the machine is changed without toggling back through Local and losing the box on the way. #}

Local images: no setup. Remote images: configure the server in Settings.

{# Where the share reports itself -- "Sharing…", "Ready on hpc", "Not connected yet". Under the switch rather than under the path row, because it is news about the machine and not about the file. #}
{# The page's primary action, built by views/quickViewLanding.js out of the shared File/Folder control (services/browsePicker.js) so the format hints under each word are defined in exactly one place. Always both halves, on every platform. An OME-Zarr image is a folder and an OME-TIFF is a file; which one you have is a fact about your format, and the example line under each word answers it rather than asking. This used to be one target that opened the question as a popup afterwards -- on the machines that could not answer it in one dialog, which is every machine but a Mac. #}
{# No Browse beside it any more: the pair above IS this page's file browser, and a second route to the same dialog made the big obvious target look like the slower of the two. #}
{# A live region that is always in the DOM and empty when it has nothing to say (`:empty` hides it), rather than one toggled with `hidden`: a region that appears and gains its text in the same tick is the shape screen readers miss. Same idiom as `.data-location-status` above it. #}
{# The three ways out, where the wizard link used to be and for the same reason: this page takes one pick and opens it, and anything that needs a decision first -- or that is not an import at all -- belongs somewhere else. One paragraph and `
`s rather than a block each, so this stays the single muted line the design has under the status and not a second section competing with the pair above. First, the import dialog. `id="sample-import-home"` is what binds it: views/importSample.js binds every "Import Sample..." on every surface by id, so this needs no controller of its own. A
{# The `?` the import dialog carries in its header, opening the same modal (views/importHelp.js, loaded by base.html on every page). Here rather than in the card's corner: this page is one centred vertical run and a corner-anchored icon is the only thing in it that belongs to no line. It reads as a question like the two around it, and it is the same question the dialog's own "All formats" link answers -- one catalogue, so the two surfaces cannot drift on what Plexora reads. #} Not sure what Plexora reads?
Already have samples?
Open one.

{% endif %} {% endblock %}