From 3b96bdc0e8e26ca00f0fa5ac0a9efa618b675367 Mon Sep 17 00:00:00 2001 From: Adam Cox Date: Mon, 26 Jun 2023 10:50:09 -0500 Subject: [PATCH 1/4] fix LOC date parsing by handling YYYY-MM-DD format #140 --- loc_insurancemaps/utils.py | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/loc_insurancemaps/utils.py b/loc_insurancemaps/utils.py index ee691f5a..7cda4985 100644 --- a/loc_insurancemaps/utils.py +++ b/loc_insurancemaps/utils.py @@ -228,28 +228,36 @@ def parse_location_info(self): self.extra_location_tags = location_tags def parse_date_info(self): + """ Parse the date tag from LOC item. If any errors, or missing date tag, use Battle of Agincourt.""" self.year = None self.month = None + good_month = False self.datetime = None date_tag = self.item.get("date", None) if date_tag is None: - return - - try: - dt = datetime.strptime(date_tag, "%Y-%m") - d = pytz.utc.localize(dt) - self.datetime = d - self.year = d.year - self.month = d.month - except ValueError: + logger.warning("no date tag on item") + dt = datetime.strptime("1415-10-25", "%Y-%m-%d") + else: try: - dt = datetime.strptime(date_tag, "%Y") - d = pytz.utc.localize(dt) - self.datetime = d - self.year = d.year + dt = datetime.strptime(date_tag, "%Y-%m-%d") + good_month = True except ValueError: - print("problem parsing date: " + date_tag) + try: + dt = datetime.strptime(date_tag, "%Y-%m") + good_month = True + except ValueError: + try: + dt = datetime.strptime(date_tag, "%Y") + except ValueError: + logger.warning("problem parsing date: " + date_tag) + dt = datetime.strptime("1415-10-25", "%Y-%m-%d") + + d = pytz.utc.localize(dt) + self.datetime = d + self.year = d.year + if good_month: + self.month = d.month def parse_volume_number(self): From c8a1b7835b8ae3ac8ea127a5a36662879ce617cd Mon Sep 17 00:00:00 2001 From: Adam Cox Date: Tue, 27 Jun 2023 00:49:41 -0500 Subject: [PATCH 2/4] introduce new modal component #83 --- frontend/static/css/base.css | 368 ------------------ frontend/svelte/src/components/Modal.svelte | 136 +++++++ .../src/components/buttons/InfoButton.svelte | 27 ++ 3 files changed, 163 insertions(+), 368 deletions(-) create mode 100644 frontend/svelte/src/components/Modal.svelte create mode 100644 frontend/svelte/src/components/buttons/InfoButton.svelte diff --git a/frontend/static/css/base.css b/frontend/static/css/base.css index 20949642..aaa789ec 100644 --- a/frontend/static/css/base.css +++ b/frontend/static/css/base.css @@ -5909,374 +5909,6 @@ button.close { -webkit-appearance: none; appearance: none; } -.modal-open { - overflow: hidden; -} -.modal { - position: fixed; - top: 0; - right: 0; - bottom: 0; - left: 0; - z-index: 1050; - display: none; - overflow: hidden; - -webkit-overflow-scrolling: touch; - outline: 0; -} -.modal.fade .modal-dialog { - -webkit-transform: translate(0, -25%); - -ms-transform: translate(0, -25%); - -o-transform: translate(0, -25%); - transform: translate(0, -25%); - -webkit-transition: -webkit-transform 0.3s ease-out; - -moz-transition: -moz-transform 0.3s ease-out; - -o-transition: -o-transform 0.3s ease-out; - transition: transform 0.3s ease-out; -} -.modal.in .modal-dialog { - -webkit-transform: translate(0, 0); - -ms-transform: translate(0, 0); - -o-transform: translate(0, 0); - transform: translate(0, 0); -} -.modal-open .modal { - overflow-x: hidden; - overflow-y: auto; -} -.modal-dialog { - position: relative; - width: auto; - margin: 10px; -} -.modal-content { - position: relative; - background-color: #fff; - background-clip: padding-box; - border: 1px solid #999; - border: 1px solid rgba(0, 0, 0, 0.2); - border-radius: 6px; - -webkit-box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5); - box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5); - outline: 0; -} -.modal-backdrop { - position: fixed; - top: 0; - right: 0; - bottom: 0; - left: 0; - z-index: 1040; - background-color: #000; -} -.modal-backdrop.fade { - filter: alpha(opacity=0); - opacity: 0; -} -.modal-backdrop.in { - filter: alpha(opacity=50); - opacity: 0.5; -} -.modal-header { - padding: 15px; - border-bottom: 1px solid #e5e5e5; -} -.modal-header .close { - margin-top: -2px; -} -.modal-title { - margin: 0; - line-height: 1.42857143; -} -.modal-body { - position: relative; - padding: 15px; -} -.modal-footer { - padding: 15px; - text-align: right; - border-top: 1px solid #e5e5e5; -} -.modal-footer .btn + .btn { - margin-bottom: 0; - margin-left: 5px; -} -.modal-footer .btn-group .btn + .btn { - margin-left: -1px; -} -.modal-footer .btn-block + .btn-block { - margin-left: 0; -} -.modal-scrollbar-measure { - position: absolute; - top: -9999px; - width: 50px; - height: 50px; - overflow: scroll; -} -@media (min-width: 768px) { - .modal-dialog { - width: 600px; - margin: 30px auto; - } - .modal-content { - -webkit-box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5); - box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5); - } - .modal-sm { - width: 300px; - } -} -@media (min-width: 992px) { - .modal-lg { - width: 900px; - } -} -.tooltip { - position: absolute; - z-index: 1070; - display: block; - font-family: 'Lato', sans-serif; - font-style: normal; - font-weight: 400; - line-height: 1.42857143; - line-break: auto; - text-align: left; - text-align: start; - text-decoration: none; - text-shadow: none; - text-transform: none; - letter-spacing: normal; - word-break: normal; - word-spacing: normal; - word-wrap: normal; - white-space: normal; - font-size: 14px; - filter: alpha(opacity=0); - opacity: 0; -} -.tooltip.in { - filter: alpha(opacity=90); - opacity: 0.9; -} -.tooltip.top { - padding: 5px 0; - margin-top: -3px; -} -.tooltip.right { - padding: 0 5px; - margin-left: 3px; -} -.tooltip.bottom { - padding: 5px 0; - margin-top: 3px; -} -.tooltip.left { - padding: 0 5px; - margin-left: -3px; -} -.tooltip.top .tooltip-arrow { - bottom: 0; - left: 50%; - margin-left: -5px; - border-width: 5px 5px 0; - border-top-color: #000; -} -.tooltip.top-left .tooltip-arrow { - right: 5px; - bottom: 0; - margin-bottom: -5px; - border-width: 5px 5px 0; - border-top-color: #000; -} -.tooltip.top-right .tooltip-arrow { - bottom: 0; - left: 5px; - margin-bottom: -5px; - border-width: 5px 5px 0; - border-top-color: #000; -} -.tooltip.right .tooltip-arrow { - top: 50%; - left: 0; - margin-top: -5px; - border-width: 5px 5px 5px 0; - border-right-color: #000; -} -.tooltip.left .tooltip-arrow { - top: 50%; - right: 0; - margin-top: -5px; - border-width: 5px 0 5px 5px; - border-left-color: #000; -} -.tooltip.bottom .tooltip-arrow { - top: 0; - left: 50%; - margin-left: -5px; - border-width: 0 5px 5px; - border-bottom-color: #000; -} -.tooltip.bottom-left .tooltip-arrow { - top: 0; - right: 5px; - margin-top: -5px; - border-width: 0 5px 5px; - border-bottom-color: #000; -} -.tooltip.bottom-right .tooltip-arrow { - top: 0; - left: 5px; - margin-top: -5px; - border-width: 0 5px 5px; - border-bottom-color: #000; -} -.tooltip-inner { - max-width: 200px; - padding: 3px 8px; - color: #fff; - text-align: center; - background-color: #000; - border-radius: 4px; -} -.tooltip-arrow { - position: absolute; - width: 0; - height: 0; - border-color: transparent; - border-style: solid; -} -.popover { - position: absolute; - top: 0; - left: 0; - z-index: 1060; - display: none; - max-width: 276px; - padding: 1px; - font-family: 'Lato', sans-serif; - font-style: normal; - font-weight: 400; - line-height: 1.42857143; - line-break: auto; - text-align: left; - text-align: start; - text-decoration: none; - text-shadow: none; - text-transform: none; - letter-spacing: normal; - word-break: normal; - word-spacing: normal; - word-wrap: normal; - white-space: normal; - font-size: 16px; - background-color: #fff; - background-clip: padding-box; - border: 1px solid #ccc; - border: 1px solid rgba(0, 0, 0, 0.2); - border-radius: 6px; - -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); - box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); -} -.popover.top { - margin-top: -10px; -} -.popover.right { - margin-left: 10px; -} -.popover.bottom { - margin-top: 10px; -} -.popover.left { - margin-left: -10px; -} -.popover > .arrow { - border-width: 11px; -} -.popover > .arrow, -.popover > .arrow:after { - position: absolute; - display: block; - width: 0; - height: 0; - border-color: transparent; - border-style: solid; -} -.popover > .arrow:after { - content: ""; - border-width: 10px; -} -.popover.top > .arrow { - bottom: -11px; - left: 50%; - margin-left: -11px; - border-top-color: #999999; - border-top-color: rgba(0, 0, 0, 0.25); - border-bottom-width: 0; -} -.popover.top > .arrow:after { - bottom: 1px; - margin-left: -10px; - content: " "; - border-top-color: #fff; - border-bottom-width: 0; -} -.popover.right > .arrow { - top: 50%; - left: -11px; - margin-top: -11px; - border-right-color: #999999; - border-right-color: rgba(0, 0, 0, 0.25); - border-left-width: 0; -} -.popover.right > .arrow:after { - bottom: -10px; - left: 1px; - content: " "; - border-right-color: #fff; - border-left-width: 0; -} -.popover.bottom > .arrow { - top: -11px; - left: 50%; - margin-left: -11px; - border-top-width: 0; - border-bottom-color: #999999; - border-bottom-color: rgba(0, 0, 0, 0.25); -} -.popover.bottom > .arrow:after { - top: 1px; - margin-left: -10px; - content: " "; - border-top-width: 0; - border-bottom-color: #fff; -} -.popover.left > .arrow { - top: 50%; - right: -11px; - margin-top: -11px; - border-right-width: 0; - border-left-color: #999999; - border-left-color: rgba(0, 0, 0, 0.25); -} -.popover.left > .arrow:after { - right: 1px; - bottom: -10px; - content: " "; - border-right-width: 0; - border-left-color: #fff; -} -.popover-title { - padding: 8px 14px; - margin: 0; - font-size: 16px; - background-color: #f7f7f7; - border-bottom: 1px solid #ebebeb; - border-radius: 5px 5px 0 0; -} -.popover-content { - padding: 9px 14px; -} .carousel { position: relative; } diff --git a/frontend/svelte/src/components/Modal.svelte b/frontend/svelte/src/components/Modal.svelte new file mode 100644 index 00000000..420c6d52 --- /dev/null +++ b/frontend/svelte/src/components/Modal.svelte @@ -0,0 +1,136 @@ + + + + +
close('')}> + +
+ + \ No newline at end of file diff --git a/frontend/svelte/src/components/buttons/InfoButton.svelte b/frontend/svelte/src/components/buttons/InfoButton.svelte new file mode 100644 index 00000000..c0747734 --- /dev/null +++ b/frontend/svelte/src/components/buttons/InfoButton.svelte @@ -0,0 +1,27 @@ + + + + + \ No newline at end of file From 72da8a65b01ca47294cf94ed0d6be54206540764 Mon Sep 17 00:00:00 2001 From: Adam Cox Date: Tue, 27 Jun 2023 10:45:01 -0500 Subject: [PATCH 3/4] implement new modal in all contexts --- frontend/svelte/src/components/Modal.svelte | 66 +------ .../svelte/src/components/MultiTrim.svelte | 33 ---- .../src/components/VolumePreviewMap.svelte | 70 +------ frontend/svelte/src/css/interface.css | 37 ---- frontend/svelte/src/css/modal.css | 81 ++++++++ frontend/svelte/src/css/shared.css | 76 ------- frontend/svelte/src/main/Georeference.svelte | 45 ++--- frontend/svelte/src/main/Split.svelte | 47 ++--- frontend/svelte/src/main/Viewer.svelte | 46 ++--- frontend/svelte/src/main/Volume.svelte | 185 +++++++++++------- 10 files changed, 262 insertions(+), 424 deletions(-) create mode 100644 frontend/svelte/src/css/modal.css diff --git a/frontend/svelte/src/components/Modal.svelte b/frontend/svelte/src/components/Modal.svelte index 420c6d52..433b956c 100644 --- a/frontend/svelte/src/components/Modal.svelte +++ b/frontend/svelte/src/components/Modal.svelte @@ -10,6 +10,8 @@ - {if (!leaveOkay) {confirmLeave()}}}/> - - - {#if USER_TYPE == "anonymous"}

Feel free to mess around; you can't save changes unless you are logged in.

{/if}
diff --git a/frontend/svelte/src/components/VolumePreviewMap.svelte b/frontend/svelte/src/components/VolumePreviewMap.svelte index 6489ba26..770ee50a 100644 --- a/frontend/svelte/src/components/VolumePreviewMap.svelte +++ b/frontend/svelte/src/components/VolumePreviewMap.svelte @@ -23,6 +23,8 @@ import { import '../css/map-panel.css'; import {toggleFullscreen, makeLayerGroupFromVolume} from '../js/utils'; +import Modal, {getModal} from './Modal.svelte'; + export let VOLUME; export let MAPBOX_API_KEY; export let TITILER_HOST; @@ -45,8 +47,6 @@ const mainGroup = new LayerGroup({ // zIndex: 200 }); -let mapIndexLayerIds = []; - const keyImgUrl = "/static/img/key-nola-1940.png" const keyImgCaption = "Sanborn Map Key" @@ -132,9 +132,6 @@ function setLayersFromVolume(setExtent) { VOLUME.sorted_layers.main.length == mainGroup.getLayers().length ) { return } - // empty the light layers lists used for interactivity, need to be repopulated - mapIndexLayerIds = []; - mainGroup.getLayers().clear(); keyGroup.getLayers().clear(); @@ -169,25 +166,12 @@ onMount(() => { initMap(); }); -function showImgModal(imgUrl, caption) { - const modalImg = document.getElementById("modalImg") - modalImg.src = imgUrl; - modalImg.alt = caption; - document.getElementById("imgCaption").firstChild.innerHTML = caption; - document.getElementById("vModal").style.display = "block"; -} -function closeModal() { - document.getElementById("vModal").style.display = "none"; - document.getElementById("modalImg").src = ""; -} - let inFullscreen = false; - -

- Preview Map ({VOLUME.items.layers.length} layers) -

+ + {keyImgCaption} +
@@ -197,7 +181,7 @@ let inFullscreen = false; -
- - diff --git a/frontend/svelte/src/css/interface.css b/frontend/svelte/src/css/interface.css index e39c3370..82ad8d8f 100644 --- a/frontend/svelte/src/css/interface.css +++ b/frontend/svelte/src/css/interface.css @@ -194,40 +194,3 @@ tbody tr:nth-child(odd){ background-color: #ffffff; } - /* The Modal (background) */ - .modal { - display: none; - position: fixed; /* Stay in place */ - z-index: 1500; /* Sit on top */ - left: 0; - top: 0; - width: 100%; /* Full width */ - height: 100%; /* Full height */ - overflow: auto; /* Enable scroll if needed */ - background-color: rgb(0,0,0); /* Fallback color */ - background-color: rgba(0,0,0,0.4); /* Black w/ opacity */ -} - -/* Modal Content/Box */ -.modal-content { - background-color: #fefefe; - margin: 15% auto; /* 15% from the top and centered */ - padding: 20px; - border: 1px solid #888; - width: 80%; /* Could be more or less, depending on screen size */ -} - -/* The Close Button */ -.close-modal { - color: rgb(66, 66, 66); - float: right; - font-size: 28px; - font-weight: bold; -} - -.close-modal:hover, -.close-modal:focus { - color: black; - text-decoration: none; - cursor: pointer; -} \ No newline at end of file diff --git a/frontend/svelte/src/css/modal.css b/frontend/svelte/src/css/modal.css new file mode 100644 index 00000000..fa4a4368 --- /dev/null +++ b/frontend/svelte/src/css/modal.css @@ -0,0 +1,81 @@ +#topModal { + visibility: hidden; + z-index: 9999; + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: #4448; + display: flex; + align-items: center; + justify-content: center; +} +#modal { + position: relative; + border-radius: 6px; + background: #123B4F; + color: white; + /* border: 1px solid #000; */ + filter: drop-shadow(5px 5px 5px #555); + padding: 1em; + margin: 1em; + max-height: 100vh; +} +#modal img { + max-height: calc(100vh - 2em); +} + +/* mimic the .container widths */ +@media (min-width: 768px) { + #modal { + max-width: 750px; + } +} +@media (min-width: 992px) { + #modal { + max-width: 970px; + } +} +@media (min-width: 1200px) { + #modal { + max-width: 1170px; + } +} + +.visible { + visibility: visible !important; +} + +#close { + position: absolute; + top:-12px; + right:-12px; + width:24px; + height:24px; + cursor: pointer; + fill:#F44; + /* transition: transform 0.3s; */ +} + +#close:hover { + /* transform: scale(2); */ +} + +#close line { + stroke:#FFF; + stroke-width:2; +} +#modal-content { + max-width: calc(100vw - 20px); + max-height: calc(100vh - 20px); + overflow: auto; +} +#modal-content a { + text-decoration: underline; + color: white; + font-weight: bolder; +} +#modal-content button { + color: black; +} \ No newline at end of file diff --git a/frontend/svelte/src/css/shared.css b/frontend/svelte/src/css/shared.css index 14edfd76..859cb00c 100644 --- a/frontend/svelte/src/css/shared.css +++ b/frontend/svelte/src/css/shared.css @@ -91,82 +91,6 @@ tbody tr:nth-child(odd){ } } -/* The Modal (background) */ -.modal { - display: none; /* Hidden by default */ - position: fixed; /* Stay in place */ - z-index: 1500; /* Sit on top */ - padding-top: 100px; /* Location of the box */ - left: 0; - top: 0; - width: 100%; /* Full width */ - height: 100%; /* Full height */ - overflow: auto; /* Enable scroll if needed */ - background-color: rgb(0,0,0); /* Fallback color */ - background-color: rgba(0,0,0,0.9); /* Black w/ opacity */ - } - - /* Modal Content (Image) */ - .modal-content { - margin: auto; - display: block; - padding: 15px 15px 0px 15px; - width: 90%; - max-width: 800px; - } - - .modal-content img { - width: 100%; -} - - /* Caption of Modal Image (Image Text) - Same Width as the Image */ - #caption { - margin: auto; - display: block; - width: 80%; - max-width: 700px; - text-align: center; - color: #ccc; - padding: 10px 0; - height: 150px; - } - - /* Add Animation - Zoom in the Modal */ - .modal-content, #caption { - animation-name: zoom; - animation-duration: 0.3s; - } - - @keyframes zoom { - from {transform:scale(0)} - to {transform:scale(1)} - } - - /* The Close Button */ - .close-vmodal { - position: absolute; - top: 15px; - right: 35px; - color: #ffffff; - font-size: 50px; - font-weight: bold; - transition: 0.3s; - opacity: 1; - } - - .close-vmodal:hover, - .close-vmodal:focus { - color: #bbb; - text-decoration: none; - cursor: pointer; - } - - /* 100% Image Width on Smaller Screens */ - @media only screen and (max-width: 700px){ - .modal-content { - width: 100%; - } - } .reloading-btn.active { color: white; diff --git a/frontend/svelte/src/main/Georeference.svelte b/frontend/svelte/src/main/Georeference.svelte index 723511eb..e81e3545 100644 --- a/frontend/svelte/src/main/Georeference.svelte +++ b/frontend/svelte/src/main/Georeference.svelte @@ -57,6 +57,7 @@ import { } from '../js/utils'; import TitleBar from '../components/TitleBar.svelte'; +import Modal, {getModal} from '../components/Modal.svelte'; export let USER; export let SESSION_LENGTH; @@ -119,27 +120,19 @@ if (DOCUMENT.lock_enabled && (DOCUMENT.lock_details.user.name == USER)) { } $: enableSave = gcpList.length >= 3 && enableButtons; -// let disableInterface = LOCK.enabled; -// let disableReason = LOCK.type == "unauthenticated" ? LOCK.type : LOCK.stage; -// let leaveOkay = true; -// if (LOCK.stage == "in-progress") { -// leaveOkay = false; -// } - // show the extend session prompt 15 seconds before the session expires setTimeout(promptRefresh, (SESSION_LENGTH*1000) - 15000) let autoRedirect; function promptRefresh() { if (!leaveOkay) { - const modal = document.getElementById("expirationModal"); - modal.style.display = "block"; + getModal('modal-expiration').open() leaveOkay = true; autoRedirect = setTimeout(cancelAndRedirectToDetail, 15000); } } -const nextPage = DOCUMENT.layer ? DOCUMENT.layer.urls.resource : DOCUMENT.urls.resource; +const nextPage = VOLUME.urls.summary; function cancelAndRedirectToDetail() { process("cancel"); window.location.href=nextPage; @@ -510,6 +503,7 @@ onMount(() => { loadIncomingGCPs(); disabledMap(disableInterface) inProgress = false; + if (!USER) { getModal('modal-anonymous').open() } }); function disabledMap(disabled) { @@ -802,7 +796,6 @@ function process(operation){ if (operation == "extend-session") { leaveOkay = false; clearTimeout(autoRedirect) - document.getElementById("expirationModal").style.display = "none"; setTimeout(promptRefresh, (SESSION_LENGTH*1000) - 10000) } @@ -938,23 +931,21 @@ const iconLinks = [ {if (!leaveOkay) {confirmLeave()}}} on:unload={cleanup}/>

Create 3 or more ground control points to georeference this document. To create a ground control point, first click on a location in the left panel, then find and click on the corresponding location in right panel. Learn more

- -{#if !USER} - -{/if} + +

This georeferencing session is expiring, and will be cancelled soon.

+ +
+ + +

Feel free to experiment with the interface, but submit your work you must + sign in or + sign up. +

+
{#if disableInterface} diff --git a/frontend/svelte/src/main/Split.svelte b/frontend/svelte/src/main/Split.svelte index e400a14d..3c81594d 100644 --- a/frontend/svelte/src/main/Split.svelte +++ b/frontend/svelte/src/main/Split.svelte @@ -39,6 +39,7 @@ import Styles from '../js/ol-styles'; import TitleBar from '../components/TitleBar.svelte'; import {toggleFullscreen} from '../js/utils'; +import Modal, {getModal} from '../components/Modal.svelte'; const styles = new Styles(); @@ -75,8 +76,7 @@ setTimeout(promptRefresh, (SESSION_LENGTH*1000) - 10000) let autoRedirect; function promptRefresh() { if (!leaveOkay) { - const modal = document.getElementById("expirationModal"); - modal.style.display = "block"; + getModal('modal-expiration').open() leaveOkay = true; autoRedirect = setTimeout(cancelAndRedirectToDetail, 10000); } @@ -262,6 +262,7 @@ $: { onMount(() => { docView = new DocViewer("doc-viewer"); resetInterface(); + if (!USER) { getModal('modal-anonymous').open() } }); $: { @@ -308,7 +309,6 @@ function process(operation) { if (operation == "extend-session") { leaveOkay = false; clearTimeout(autoRedirect) - document.getElementById("expirationModal").style.display = "none"; setTimeout(promptRefresh, (SESSION_LENGTH*1000) - 10000) } @@ -384,30 +384,25 @@ let inFullscreen = false; {if (!leaveOkay) {confirmLeave()}}} on:unload={cleanup}/> - + +

This preparation session is expiring, and will be cancelled soon.

+ +
+ + +

Feel free to experiment with the interface, but submit your work you must + sign in or + sign up. +

+
+ + +

This document has already been prepared!

+
-{#if !USER} - -{/if} - -

{currentTxt} Learn more

diff --git a/frontend/svelte/src/main/Viewer.svelte b/frontend/svelte/src/main/Viewer.svelte index a8df7f83..58dc6f48 100644 --- a/frontend/svelte/src/main/Viewer.svelte +++ b/frontend/svelte/src/main/Viewer.svelte @@ -43,6 +43,7 @@ import VectorLayer from 'ol/layer/Vector'; import {MouseWheelZoom, defaults} from 'ol/interaction'; import {makeTitilerXYZUrl, makeLayerGroupFromVolume, makeBasemaps} from '../js/utils'; +import Modal, {getModal} from '../components/Modal.svelte' export let PLACE; export let MAPBOX_API_KEY; @@ -59,8 +60,6 @@ const tileGrid = createXYZ({ tileSize: 512, }); -let showAboutPanel = false; - let homeExtent; if (VOLUMES.length > 0) { homeExtent = createEmpty(); @@ -410,30 +409,25 @@ function getCompletedStr(id) { return `${volumeLookup[id].progress.georef_ct}/${volumeLookup[id].progress.unprep_ct+volumeLookup[id].progress.prep_ct+volumeLookup[id].progress.georef_ct}` } - -{#if showAboutPanel} -
-
-

Using this Viewer

-
    -
  • Use - / - / - , or the slider, - to change layer opacity
  • -
  • Share the browser URL at any time to retain current location and layer settings
  • -
-

About the Maps

-

These historical fire insurance maps were originally created by the Sanborn Map Company, and provided here via the Library of Congress collection.

-

In early 2022, participants in a crowdsourcing project georeferenced all of the Louisiana maps you see here, eventually creating these seamless mosaic overlays. These comprise 1,500 individual sheets from 270 different Sanborn atlases, covering of over 130 different locations.

-

Further Development

-

If you are interested in supporting this site get in touch. To get more Sanborn maps on here, please fill out this form.

-

To learn much more about the entire project, head to ohmg.dev.

- -
-
-{/if} + + +

Using this Viewer

+
    +
  • Use + / + / + , or the slider, + to change layer opacity
  • +
  • Share the browser URL at any time to retain current location and layer settings
  • +
+

About the Maps

+

These historical fire insurance maps were originally created by the Sanborn Map Company, and provided here via the Library of Congress collection.

+

In early 2022, participants in a crowdsourcing project georeferenced all of the Louisiana maps you see here, eventually creating these seamless mosaic overlays. These comprise 1,500 individual sheets from 270 different Sanborn atlases, covering of over 130 different locations.

+

Further Development

+

If you are interested in supporting this site get in touch. To get more Sanborn maps on here, please fill out this form.

+

To learn much more about the entire project, head to ohmg.dev.

+
+
{/if} diff --git a/frontend/svelte/src/main/Volume.svelte b/frontend/svelte/src/main/Volume.svelte index 3dd1be21..303cdc05 100644 --- a/frontend/svelte/src/main/Volume.svelte +++ b/frontend/svelte/src/main/Volume.svelte @@ -3,8 +3,14 @@ import { slide } from 'svelte/transition'; import Icon from 'svelte-icons-pack/Icon.svelte'; import FiTool from 'svelte-icons-pack/fi/FiTool'; +import FiScissors from 'svelte-icons-pack/fi/FiScissors'; import FiRefreshCcw from 'svelte-icons-pack/fi/FiRefreshCcw'; import FiExternalLink from 'svelte-icons-pack/fi/FiExternalLink'; +import FiCrop from 'svelte-icons-pack/fi/FiCrop'; +import FiHome from 'svelte-icons-pack/fi/FiHome'; +import FiTrash from 'svelte-icons-pack/fi/FiTrash'; +import FiCheck from 'svelte-icons-pack/fi/FiCheck'; +import FiX from 'svelte-icons-pack/fi/FiX'; import {getCenter} from 'ol/extent'; @@ -14,6 +20,10 @@ import VolumePreviewMap from "../components/VolumePreviewMap.svelte"; import MultiTrim from "../components/MultiTrim.svelte"; import ConditionalDoubleChevron from '../components/ConditionalDoubleChevron.svelte'; +import Modal, {getModal} from '../components/Modal.svelte'; + +import InfoButton from '../components/buttons/InfoButton.svelte'; + import {makeTitilerXYZUrl} from '../js/utils'; export let VOLUME; @@ -42,6 +52,9 @@ $: showNonmaps = hash == 'nonmaps'; $: showMultimask = hash == 'multimask'; $: showDownload = hash == 'download'; +let modalDocSrc; +let modalDocTitle; + let refreshingLookups = false; let layerCategories = [ @@ -61,18 +74,6 @@ function setLayerCategoryLookup(VOLUME) { } $: setLayerCategoryLookup(VOLUME) -function showImgModal(imgUrl, caption) { - const modalImg = document.getElementById("modalImg") - modalImg.src = imgUrl; - modalImg.alt = caption; - document.getElementById("imgCaption").firstChild.innerHTML = caption; - document.getElementById("vModal").style.display = "block"; -} -function closeModal() { - document.getElementById("vModal").style.display = "none"; - document.getElementById("modalImg").src = ""; -} - let intervalId; function manageAutoReload(run) { if (run) { @@ -160,7 +161,7 @@ let settingKeyMapLayer = false; const sideLinks = [ { - display: "Open in main viewer", + display: `View all ${VOLUME.locale.display_name} mosaics`, url: VOLUME.urls.viewer, external: true, }, @@ -180,13 +181,47 @@ function setHash(newHash) { - + + {modalDocTitle} + + +

The Mosaic Preview shows progress toward a full mosaic of this item's content—as documents are georeferenced, they will automatically appear here. You can also view this mosaic alongside all other mosaics for this locale: {VOLUME.locale.display_name}

+
+ +

The Georeferencing Overview provides a per-document summary and access point to the entire georeferencing process for this item's content.

+
+ +

Each document in the Unprepared section must be evaluated individually, and, if it contains more than one mapped area, split into separate pieces.

+
+ +

Content in the Prepared section is ready to be georeferenced. You can also decide here if a particular document should be moved to the Non-map Content section, for example if it is a title page or text index (this designation can be easily reversed).

+
+ +

The Georeferenced section holds all content that has been spatially rectified, though you can still edit the control points for any layer whose georeferencing should be improved. Use the Classify Layers button to sort layers into different categories, if applicable. For example, if a Key Map is present, classify it here so other interfaces will treat it appropriately.

+
+ +

The MultiMask is a mechanism for trimming the margins from every layer in a way that guarantees a seamless mosaic across this item's content.

+

How to create a MultiMask

+
    +
  • Use to start a mask for a particular layer.
  • +
  • Use to delete an existing mask.
  • +
  • Use to save your work (do this often!).
  • +
  • Use to discard all changes since the last save.
  • +
+

Important Notes

+
    +
  • You must be signed in to save your work, so don't get started before you are signed in!
  • +
  • The vertices of every adjacent mask should be snapped together
  • +
  • You can drag existing vertices to snap them to others, but this is sometimes "sticky" and takes a couple of tries.
  • +
  • If a mosaic is generated for this item, only layers that have been masked will be included in the mosaic.
  • +
+
+ +

The Non-Map Content section holds documents (or document fragments) that are not maps, like a title page or text index.

+
+ +

+
@@ -203,8 +238,9 @@ function setHash(newHash) { +
{#if showMap}
@@ -212,17 +248,21 @@ function setHash(newHash) { {#each reinitMap as key (key)} {/each} -
-

The preview map shows progress toward a full mosaic of this volume's content.

-
{/if}
- -

Georeferencing Overview

-
+ + {#if refreshingLookups} +
+ {/if} +
@@ -242,11 +282,6 @@ function setHash(newHash) { {/if}
-
- {#if refreshingLookups} -
- {/if} -
{#if USER_TYPE != "anonymous"} +
{#if showUnprepared}
-

Unprepared sheets need to be evaluated, and, if they contain more than one mapped area, split into separate pieces.

- {#if VOLUME.items.unprepared.length == 0} -

- {#if VOLUME.sheet_ct.loaded == 0} - Sheets will appear here as they are loaded. - {:else} - All sheets have been prepared. - {/if} -

- {:else} -

Choose a sheet and click prepare → to start the process.

{#each VOLUME.items.unprepared as document}
- {showImgModal(document.urls.image, document.title)}} src={document.urls.thumbnail} alt={document.title}> + { + modalDocSrc=document.urls.image; + modalDocTitle=document.title; + getModal('modal-doc-view').open()}} + src={document.urls.thumbnail} + alt={document.title} + >
{#if document.lock_enabled}
    @@ -313,7 +345,6 @@ function setHash(newHash) {
{/each}
- {/if}
{/if}
@@ -328,19 +359,22 @@ function setHash(newHash) { {/if} +
{#if showPrepared}
-

Once a sheet has been prepared it is ready to be georeferenced.

- {#if VOLUME.items.prepared.length == 0} -

Documents will accumulate here when they are ready to be georeferenced.

- {:else} -

Choose a document and click georeference → to start the process.

{#each VOLUME.items.prepared as document}
- {showImgModal(document.urls.image, document.title)}} src={document.urls.thumbnail} alt={document.title}> + { + modalDocSrc=document.urls.image; + modalDocTitle=document.title; + getModal('modal-doc-view').open()}} + src={document.urls.thumbnail} + alt={document.title} + >
{#if document.lock_enabled}
    @@ -357,7 +391,6 @@ function setHash(newHash) {
{/each}
- {/if}
{/if} @@ -367,27 +400,22 @@ function setHash(newHash) {

Georeferenced ({VOLUME.items.layers.length})

+
{#if showGeoreferenced}
-

Georeferenced documents are represented here as layers.

- {#if VOLUME.items.layers.length == 0} -

Layers will accumulate here as documents are georeferenced.

- {:else} -

- Use Set Key Map to designate which layers show the key map for this volume (if applicable). -

- {#if USER_TYPE != 'anonymous'} -
+
{#if VOLUME.items.layers.length > 0 && !settingKeyMapLayer} - + {/if} {#if settingKeyMapLayer} {/if}
- {/if}
{#each VOLUME.items.layers as layer}
@@ -426,7 +454,7 @@ function setHash(newHash) {
{/each}
- {/if} +
{/if} @@ -436,6 +464,7 @@ function setHash(newHash) {

MultiMask ({mmLbl})

+
{#if showMultimask}
@@ -444,9 +473,6 @@ function setHash(newHash) { USER_TYPE={USER_TYPE} MAPBOX_API_KEY={MAPBOX_API_KEY} TITILER_HOST={TITILER_HOST} /> -
-

Only layers with a mask will be included in MosaicJSON or GeoTIFF mosaic output.

-
{/if} @@ -456,10 +482,10 @@ function setHash(newHash) {

Non-Map Content ({VOLUME.items.nonmaps.length})

+ {#if showNonmaps}
-

Some content may not contain a map to be georeferenced, such as a title page or a text index. You can designate such content in the "Prepared" section above and it will appear here.

{#each VOLUME.items.nonmaps as nonmap}
@@ -523,9 +549,13 @@ function setHash(newHash) {

@@ -595,6 +625,19 @@ button.section-toggle-btn:disabled, button.section-toggle-btn:disabled > a { color: grey; } +.section-title-bar { + display:flex; + flex-direction:row; + justify-content:space-between; + align-items:center; +} + +.subsection-title-bar { + display:flex; + flex-direction:row; + justify-content:space-between; + align-items:center; +} .documents-column { display: flex; From 4406ed333c6c1302c57834a461edb33ce42bda11 Mon Sep 17 00:00:00 2001 From: Adam Cox Date: Fri, 30 Jun 2023 08:44:52 -0500 Subject: [PATCH 4/4] drop out of fullscreen before opening expiration modal --- frontend/svelte/src/main/Georeference.svelte | 1 + frontend/svelte/src/main/Split.svelte | 1 + 2 files changed, 2 insertions(+) diff --git a/frontend/svelte/src/main/Georeference.svelte b/frontend/svelte/src/main/Georeference.svelte index e81e3545..bfd2b33b 100644 --- a/frontend/svelte/src/main/Georeference.svelte +++ b/frontend/svelte/src/main/Georeference.svelte @@ -126,6 +126,7 @@ setTimeout(promptRefresh, (SESSION_LENGTH*1000) - 15000) let autoRedirect; function promptRefresh() { if (!leaveOkay) { + if (document.fullscreenElement != null) { document.exitFullscreen(); } getModal('modal-expiration').open() leaveOkay = true; autoRedirect = setTimeout(cancelAndRedirectToDetail, 15000); diff --git a/frontend/svelte/src/main/Split.svelte b/frontend/svelte/src/main/Split.svelte index 3c81594d..2302a4e5 100644 --- a/frontend/svelte/src/main/Split.svelte +++ b/frontend/svelte/src/main/Split.svelte @@ -76,6 +76,7 @@ setTimeout(promptRefresh, (SESSION_LENGTH*1000) - 10000) let autoRedirect; function promptRefresh() { if (!leaveOkay) { + if (document.fullscreenElement != null) { document.exitFullscreen(); } getModal('modal-expiration').open() leaveOkay = true; autoRedirect = setTimeout(cancelAndRedirectToDetail, 10000);