Initial commit

This commit is contained in:
Nasir Anthony Montalvo
2025-11-13 14:48:58 -06:00
committed by GitHub
commit 526096840e
2349 changed files with 19464 additions and 0 deletions

View File

@@ -0,0 +1,48 @@
{% comment %}
Embed an interactive viewer to display 3d model files in glTF/GLB format (.glb or .gltf).
Uses the model-viewer component, https://modelviewer.dev/
This assumes that the item's object_location is a .glb or .gltf file.
If an image_small is set in the metadata, that image is used as a "poster" and model is not loaded until user clicks.
{% endcomment %}
<!-- import model-viewer component from CDN -->
<script type="module" src="https://ajax.googleapis.com/ajax/libs/model-viewer/3.1.1/model-viewer.min.js"></script>
{% if page.image_small %}
<style>
/* add styles for poster image and load button */
#poster-image {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
background-image: url("{{ page.image_small | relative_url }}");
background-size: contain;
background-repeat: no-repeat;
background-position: center;
cursor: pointer;
}
#load-model-btn {
position: absolute;
left: 50%;
top: 50%;
transform: translate3d(-50%, -50%, 0);
}
</style>{% endif %}
<!-- add 3d viewer to page -->
<div class="ratio ratio-4x3">
<model-viewer id="item-model-viewer" alt="{{ page.image_alt_text | default: page.description | default: page.title | escape }}" src="{{ page.object_location | relative_url }}" shadow-intensity="1" camera-controls touch-action="pan-y" {% if page.image_small %}reveal="manual"{% endif %}>
{% if page.image_small %}
<div id="poster-image" slot="poster"></div>
<button id="load-model-btn" class="btn btn-lg btn-primary" slot="poster">Load 3D Model</button>
{% endif %}
</model-viewer>
</div>
{% if page.image_small %}
<script>
/* load model on user click */
var itemModelViewer = document.querySelector('#item-model-viewer');
itemModelViewer.addEventListener('click', () => itemModelViewer.dismissPoster());
</script>
{% endif %}

View File

@@ -0,0 +1,10 @@
{% comment %}
Adds html audio element with source listed in object_location.
Provides a fallback to download the file.
{%- endcomment -%}
<audio controls class="w-100">
<source src="{{ page.object_location | relative_url }}">
Your browser does not support the audio element. Please <a href="{{ page.object_location | relative_url }}">download the audio file</a>.
</audio>

View File

@@ -0,0 +1,11 @@
{% comment %}
Adds Bootstrap styled breadcrumbs to page.
By default the crumbs are: Home (index.html) / Items (browse.html) / current page title (from the metadata, truncated to 10 words max).
{%- endcomment -%}
<ol class="breadcrumb">
<li class="breadcrumb-item"><a class="text-dark" href="{{ '/' | relative_url }}">Home</a></li>
<li class="breadcrumb-item"><a class="text-dark" href="{{ '/browse.html' | relative_url }}">Items</a></li>
<li class="breadcrumb-item active text-dark" aria-current="page">{{ page.title | truncatewords: 10 }}</li>
</ol>

View File

@@ -0,0 +1,100 @@
{% comment %}
Adds previous and next button arrows to provide navigation between items.
Requires cb_page_gen plugin.
The item order follows the order in the metadata CSV, so pre-sort the CSV to the desired order.
{%- endcomment -%}
<div class="text-center">
<a class="btn btn-secondary" href="{{ page.previous_item | relative_url }}" id="prev-page-button">&laquo; Previous</a>
<a class="btn btn-secondary" href="{{ '/browse.html' | relative_url }}">Back to Browse</a>
<a class="btn btn-secondary" href="{{ page.next_item | relative_url }}" id="next-page-button">Next &raquo;</a>
</div>
<div id="item-nav">
<div class="d-none d-md-block">
<a class="previous btn btn-lg btn-secondary" href="{{ page.previous_item | relative_url }}">&laquo;</a>
<a class="next btn btn-lg btn-secondary" href="{{ page.next_item | relative_url }}">&raquo;</a>
</div>
</div>
<script>
function leftArrowPressed() {
location.href = document.getElementById("prev-page-button").href;
};
function rightArrowPressed() {
location.href = document.getElementById("next-page-button").href;
};
function leftModalArrowPressed() {
// Get the modal element.
var modalshow = document.querySelector(".modal.show");
// If the modal exists, get the prev button element.
if (modalshow) {
const prevButton = modalshow.querySelector(".prev-child-button");
// If the prev button exists, click it.
if (prevButton) {
prevButton.click();
}
}
};
function rightModalArrowPressed() {
// Get the modal element.
var modalshow = document.querySelector(".modal.show");
// If the modal exists, get the prev button element.
if (modalshow) {
const nextButton = modalshow.querySelector(".next-child-button");
// If the prev button exists, click it.
if (nextButton) {
nextButton.click();
}
}
};
function isModalShown() {
// Get the modal element.
const modal = document.querySelector(".modal.show");
// Check if the modal has the "show" class.
return modal && modal.classList.contains("show");
};
function isSpotlightModalShown() {
// Get the modal element.
const spotlight = document.getElementById("spotlight");
// Check if the modal has the "show" class.
return spotlight && spotlight.classList.contains("show");
};
document.onkeydown = function (evt) {
if (isSpotlightModalShown()) {
} else if (isModalShown()) {
// The modal is shown.
evt = evt || window.event;
switch (evt.keyCode) {
case 37:
leftModalArrowPressed();
break;
case 39:
rightModalArrowPressed();
break;
}
}
else {
// The modal is not shown.
evt = evt || window.event;
switch (evt.keyCode) {
case 37:
leftArrowPressed();
break;
case 39:
rightArrowPressed();
break;
}
}
};
</script>

View File

@@ -0,0 +1,10 @@
{% comment %}
Adds html audio element with source listed in object_location of a child item.
Provides a fallback to download the file.
{%- endcomment -%}
<audio controls class="w-100">
<source src="{{ child.object_location | relative_url }}">
Your browser does not support the audio element. Please <a href="{{ child.object_location | relative_url }}">download the audio file</a>.
</audio>

View File

@@ -0,0 +1,14 @@
{% comment %}
Adds a basic citation box for child item with reference link to the child modal.
{%- endcomment -%}
<div class="card mb-2">
<div class="card-header">Attribution</div>
<div class="card-body">
<dl>
<dt>Citation:</dt>
<dd>"{{ child.title | default: page.title }}", {{ site.title }}, {% if site.organization-name %}{{ site.organization-name }}, {% endif %}<a href="{{ page.url | absolute_url }}#{{ child.objectid }}">{{ page.url | absolute_url }}#{{ child.objectid }}</a></dd>
</dl>
</div>
</div>

View File

@@ -0,0 +1,47 @@
{% comment %}
Adds button links for compound object parent item page.
If item has date to Timeline, if item has lat/long to Map, if item has child objects with object_location it adds Download options for each.
Styled as a Bootstrap btn-group.
{%- endcomment -%}
<div class="btn-group my-3" role="group" aria-label="Item options">
{% if page.object_transcript %}<button class="btn btn-outline-primary" type="button" data-bs-toggle="collapse" data-bs-target="#collapseTranscript" aria-expanded="false" aria-controls="collapseTranscript">View Transcript</button>{% endif %}
{% if page.date %}{%- capture year -%}{% if page.date contains "-" %}{{ page.date | split: "-" | first }}{% elsif page.date contains "/" %}{{ page.date | split: "/" | last }}{% else %}{{ page.date }}{% endif %}{%- endcapture -%}
<a href="{{ year | strip | prepend: '/timeline.html#y' | relative_url }}" class="btn btn-outline-primary">View on Timeline</a>{% endif %}
{% if page.latitude and page.longitude %}
<a href="{{ '/map.html?location=' | append: page.latitude | append: ',' | append: page.longitude | append: '&marker=' | append: page.objectid | relative_url }}" class="btn btn-outline-primary">View on Map</a>{% endif %}
<div class="btn-group" role="group">
<button class="btn btn-outline-primary dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
Download
</button>
<ul class="dropdown-menu">
{% if page.object_location %}<li><a target="_blank" rel="noopener" href="{{ page.object_location | relative_url }}" class="dropdown-item">{{ page.title }} ({{ page.format | split: '/' | last | upcase }})</a></li>{% endif %}
{% for child in children %}
{% unless child.object_location == nil %}
<li>
<a target="_blank" rel="noopener" href="{{ child.object_location | relative_url }}" class="dropdown-item">
{% if page.title != child.title and child.title != nil %}{{ child.title | truncatewords: 3 }}{% else %}Item {{ forloop.index }}{% endif %}
{% if child.format %}({{ child.format | split: '/' | last | upcase }}){% endif %}
</a>
</li>
{% endunless %}
{% endfor %}
</ul>
</div>
</div>
{% if page.object_transcript %}
<div class="collapse mt-3" id="collapseTranscript">
<div class="card card-body text-start">
{% assign transcript_type = page.object_transcript | slice: 0,1 %}
{% if transcript_type == '/' %}
{% assign transcript_location = page.object_transcript | remove_first: '/' %}
{% assign transcript = site.pages | where: 'path', transcript_location | first %}
{{ transcript.content | markdownify }}
{% else %}
{{ page.object_transcript | markdownify }}
{% endif %}
</div>
</div>
{% endif %}

View File

@@ -0,0 +1,165 @@
{% comment %}
Creates a gallery of thumbnails images or icons for each child item in a compound object. The thumb defaults to image_thumb or image_small, otherwise an icon is added based on the display_template or format of the child item.
Each child item is given a popup modal with full display and metadata information. The display is chosen based on the display_template of the child item.
This include requires the Liquid object "child" to be present! The item display requires the compound object item includes in "item/child/".
{% endcomment %}
<div class="row row-cols-2 row-cols-lg-4 g-2">
{% for child in children %}
<div class="col">
<div class="card h-100">
<div class="my-auto">
<div class="card-body text-center" id="{{ child.objectid }}Card">
{% if child.title %}<div class="small text-dark mb-2">{{ child.title | truncatewords: 4 }}</div>{% endif %}
<div class="mb-2">
{% if child.image_thumb or child.image_small %}
<img class="img-thumbnail compound-thumb" src="{{ child.image_thumb | default: child.image_small | relative_url }}" alt="{{ child.image_alt_text | default: child.description | default: child.title | escape }}">
{% else %}
<svg class="bi text-body compound-thumb" fill="currentColor" aria-hidden="true">
{%- assign icon_template = child.display_template | default: item.format -%}
<use xlink:href="{{ '/assets/css/cb-icons.svg' | relative_url }}#{% if icon_template contains 'image' %}icon-image{% elsif icon_template contains 'pdf' %}icon-pdf{% elsif icon_template contains 'audio' %}icon-audio{% elsif icon_template contains 'video' %}icon-video{% else %}icon-default{% endif %}" />
</svg>
<span class="visually-hidden">{{ child.title | escape }} - {{ child.format }}</span>
{% endif %}
</div>
<!-- child object modal button -->
<a id="item-{{ forloop.index }}"
role="button"
data-bs-toggle="modal"
href="#{{ child.objectid }}"
onclick="window.location.hash='{{ child.objectid }}'"
class="btn btn-sm btn-outline-secondary small stretched-link">
{{ child.display_template | upcase | default: "Item" }} <svg class="bi icon-sprite" fill="currentColor" aria-hidden="true"><use xlink:href="{{ '/assets/css/cb-icons.svg' | relative_url }}#icon-{{ child.display_template | default: 'file'}}"/></svg>
</a>
<!-- child object modal -->
<div class="modal fade" id="{{ child.objectid }}" tabindex="-1" role="dialog" aria-labelledby="{{ child.objectid }}ModalLabel" aria-hidden="true">
<div class="modal-dialog modal-xxl">
<div class="modal-content text-start">
<div class="modal-header ">
<div class="modal-title w-100" id="{{ child.objectid }}ModalLabel">
<div class="row">
{% capture stopMedia %}{% if child.display_template == 'video' %}{% if child.object_location contains 'vimeo' %}vimeo{% elsif child.object_location contains 'youtu' %}youtube{% else %}video{% endif %}{% elsif child.display_template == 'audio' %}audio{% else %}{% endif %}{% endcapture %}
<div class="col-12 text-end">
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"
onclick="{% if stopMedia != '' %}stopMedia('{{ child.objectid }}','{{ stopMedia }}');{% endif %}history.pushState('', '', window.location.pathname)"></button>
</div>
{% capture next_index %}{% if forloop.index == forloop.length %}0{% else %}{{ forloop.index0 | plus: 1 }}{% endif %}{% endcapture %}
{% assign next_index = next_index | times: 1 %}
{% capture prev_index %}{% if forloop.index0 == 0 %}{{ forloop.length | minus: 1 }}{% else %}{{ forloop.index0 | minus: 1 }}{% endif %}{% endcapture %}
{% assign prev_index = prev_index | times: 1 %}
{% capture next_item_id %}{{ children[next_index].objectid }}{% endcapture %}
{% capture prev_item_id %}{{ children[prev_index].objectid }}{% endcapture %}
<div class="col-1 col-md-2">
<button data-bs-target="#{{ prev_item_id }}" data-bs-toggle="modal" onclick="{% if stopMedia != '' %}stopMedia('{{ child.objectid }}','{{ stopMedia }}');{% endif %}window.location.hash='{{ prev_item_id }}'" class="btn btn-outline-dark btn-sm prev-child-button" >
<svg class="bi icon-sprite" role="img" aria-label="Previous Item">
<use xlink:href="{{ '/assets/css/cb-icons.svg' | relative_url }}#arrow-left"/>
</svg>
<span class="d-none d-md-inline">Previous Item</span>
</button>
</div>
<div class="col-9 col-md-8 text-center">
<h3 class="h5">{{ page.title }}
<span class="d-none d-md-inline">-</span><span class="d-md-none"><br></span>
Item {{ forloop.index }} of {{ children | size }}
</h3>
</div>
<div class="col-1 col-md-2 text-end">
<button data-bs-target="#{{ next_item_id }}" data-bs-toggle="modal" onclick="{% if stopMedia != '' %}stopMedia('{{ child.objectid }}','{{ stopMedia }}');{% endif %}window.location.hash='{{ next_item_id }}'" class="ms-md-5 btn btn-outline-dark btn-sm next-child-button">
<span class="d-none d-md-inline">Next Item</span>
<svg class="bi icon-sprite" role="img" aria-label="Next Item">
<use xlink:href="{{ '/assets/css/cb-icons.svg' | relative_url }}#arrow-right"/>
</svg>
</button>
</div>
</div>
</div>
</div>
<div class="modal-body">
<div class="row">
<div class="col-md-8">
<div class="card mb-4 text-center">
<div class="m-2">
{% if child.display_template == 'image' %}
{% include item/child/image-gallery.html %}
{% elsif child.display_template == 'video' %}
{% if child.object_location contains 'vimeo' or child.object_location contains 'youtu' %}
{% include item/child/video-embed.html %}
{% else %}
{% include item/child/video-player.html %}
{% endif %}
{% elsif child.display_template == 'audio' %}
<div class="my-auto">
{% include item/child/audio-player.html %}
</div>
{% elsif child.display_template == 'panorama' %}
{% include item/child/panorama.html %}
{% else %}
{% include item/child/item-thumb.html %}
{% endif %}
</div>
<div class="my-2">
{% include item/child/download-buttons.html %}
</div>
</div>
</div>
<div class="col-md-4">
{% include item/child/metadata.html %}
</div>
</div>
<div class="row justify-content-center mt-4">
<div class="col-md-5 py-4">
{% include item/child/citation-box.html %}
</div>
{% if child.rights or child.rightsstatement %}
<div class="col-md-5 py-4">
{% include item/child/rights-box.html %}
</div>
{% endif %}
</div>
</div>
</div>
</div>
</div>
<!-- end child modal -->
</div>
</div>
</div>
</div>
{% endfor %}
</div>
<script>
function stopMedia(objectid, type) {
// stop media based on type
if (type == "audio") {
const mediaElement = document.querySelector(`#${ objectid } audio`);
mediaElement.pause();
//mediaElement.currentTime = 0;
}
if (type == "video") {
const mediaElement = document.querySelector(`#${ objectid } video`);
mediaElement.pause();
//mediaElement.currentTime = 0;
}
if (type == "youtube") {
const mediaElement = document.querySelector(`#${ objectid } iframe`);
const message = JSON.stringify({ event: 'command', func: 'pauseVideo', args: '' });
mediaElement.contentWindow.postMessage(message, '*');
}
if (type == "vimeo") {
const mediaElement = document.querySelector(`#${ objectid } iframe`);
mediaElement.contentWindow.postMessage('{"method":"pause"}', '*');
}
}
</script>

View File

@@ -0,0 +1,34 @@
{% comment %}
Adds child modal button links, styled as a Bootstrap btn-group.
Features:
- View Transcript -- if the item has the field "object_transcript", this button is added along with a Bootstrap collapse containing the transcript content. If the value of "object_transcript" starts with objects/ it will look for the matching transcript file in the objects fold, otherwise it will use the value directly. Both will be rendered in Markdown.
- View on Timeline -- if the item has a "date" value, links to Timeline page.
- View on Map -- if item has "latitude" and "longitude" value, links to location on map.
- Download -- if the item has "object_location" value, adds a download button along with the item format, or if the value is a YouTube or Vimeo link adds a "View on" link.
{%- endcomment -%}
<div class="btn-group my-2" role="group" aria-label="Item options">
{% if child.object_transcript %}<button class="btn btn-outline-primary" type="button" data-bs-toggle="collapse" data-bs-target="#collapseTranscript{{ child.objectid }}" aria-expanded="false" aria-controls="collapseTranscript{{ child.objectid }}">View Transcript</button>{% endif %}
{% if child.date %}{%- capture year -%}{% if child.date contains "-" %}{{ child.date | split: "-" | first }}{% elsif child.date contains "/" %}{{ child.date | split: "/" | last }}{% else %}{{ child.date }}{% endif %}{%- endcapture -%}
<a href="{{ year | strip | prepend: '/timeline.html#y' | relative_url }}" class="btn btn-outline-primary">View on Timeline</a>{% endif %}
{% if child.latitude and child.longitude %}
<a href="{{ '/map.html?location=' | append: page.latitude | append: ',' | append: page.longitude | append: '&marker=' | append: page.objectid | relative_url }}" class="btn btn-outline-primary">View on Map</a>{% endif %}
{% if child.object_location %}<a target="_blank" rel="noopener" href="{{ child.object_location | relative_url }}" class="btn btn-outline-primary">
{% if child.display_template == 'video' and child.object_location contains 'vimeo' %}View on Vimeo{% elsif child.display_template == 'video' and child.object_location contains 'youtu' %}View on YouTube{% elsif child.display_template == 'record'%}Link to Object{% else %}Download {{ child.format | split: '/' | last | default: page.display_template | upcase }}{% endif %}
</a>{% endif %}
</div>
{% if child.object_transcript %}
<div class="collapse mt-3" id="collapseTranscript{{ child.objectid }}">
<div class="card card-body text-start">
{% assign transcript_type = child.object_transcript | slice: 0,1 %}
{% if transcript_type == '/' %}
{% assign transcript_location = child.object_transcript | remove_first: '/' %}
{% assign transcript = site.pages | where: 'path', transcript_location | first %}
{{ transcript.content | markdownify }}
{% else %}
{{ child.object_transcript | markdownify }}
{% endif %}
</div>
</div>
{% endif %}

View File

@@ -0,0 +1,27 @@
{% comment %}
Internet Archive item embed.
Loads a book/pdf, video, or audio item from Internet Archive via their standard iframe embed.
The item's "objects_location" must be the full public URL to the object on IA. The item url looks something like:
book, https://archive.org/details/uidaho_gem_1903
video, https://archive.org/details/fluxusfireplace
audio, https://archive.org/details/aladore_1704_librivox
The embed works for books/pdfs, video, and audio--however, you will want to tweak the aspect ratio for different item types!
Options:
- "ratio" = use Bootstrap embed ratio options "21x9", "16x9", "4x3", or "1x1" to customize the responsive aspect ratio if not using height. 4x3 is default. (optional)
- "height" = set embed object height in px (rather than responsive size), width will be 100%, e.g. "800px" (optional)
- "style" = apply an arbitrary style to the div containing the embed. This is useful if you are trying to add a min height or custom aspect ratio. (optional)
- min height is useful for book items on mobile, e.g. "min-height: 500px;"
- custom aspect ratio may be useful for book items, e.g. "--bs-aspect-ratio: %115;"
- both e.g. "min-height: 500px;--bs-aspect-ratio: calc(3 / 4 * 100%);"
{% endcomment %}
{% assign archive_id = child.object_location | split: '/' | last %}
<div class="{% unless include.height %}ratio ratio-{{ include.ratio | default: '4x3' }}{% endunless %}"{% if include.style %} style="{{ include.style }}"{% endif %}>
<iframe title="item embed for {{ child.title | escape }}" src="https://archive.org/embed/{{ archive_id }}" {% if include.height %}class="w-100" height="{{ include.height }}"{% endif %} frameborder="0" webkitallowfullscreen="true" mozallowfullscreen="true" allowfullscreen></iframe>
</div>`

View File

@@ -0,0 +1,10 @@
{% comment %}
Adds child image in a Spotlight gallery markup.
Ensure dependencies are added by including `gallery: true` in the layout front matter calling this include.
{%- endcomment -%}
<a id="{{ child.objectid }}" class="spotlight gallery-img" {% if child.object_location %}data-download="true"{% endif %} title="{{ child.title | escape }}" href="{{ child.object_location | default: child.image_small | relative_url }}">
<img src="{{ child.image_small | relative_url }}" alt="{{ child.image_alt_text | default: child.description | default: child.title | escape }}" class="img-fluid">
<div><small class="text-dark">Click to view full screen</small></div>
</a>

View File

@@ -0,0 +1,17 @@
{% comment %}
Add a thumbnail image or icon based on format for a child item, with a object_location link (if available).
{% endcomment %}
{% if child.object_location %}<a href="{{ child.object_location | relative_url }}" target="_blank" rel="noopener">{% endif %}
{% if child.image_thumb or child.image_small %}
<img class="img-thumbnail" src="{{ child.image_small | default: child.image_thumb | relative_url }}" alt="{{ child.image_alt_text | default: child.description | default: child.title | escape }}">
{% else %}
<svg class="bi text-body" fill="currentColor" aria-hidden="true">
{%- assign icon_template = child.display_template | default: child.format -%}
<use xlink:href="{{ '/assets/css/cb-icons.svg' | relative_url }}#{% if icon_template contains 'image' %}icon-image{% elsif icon_template contains 'pdf' %}icon-pdf{% elsif icon_template contains 'audio' %}icon-audio{% elsif icon_template contains 'video' %}icon-video{% elsif icon_template contains 'record' %}icon-record{% else %}icon-default{% endif %}"/>
</svg>
<span class="visually-hidden">{{ child.title | escape }} - {{ child.format }}</span>
{% endif %}
{% if child.object_location %}</a>{% endif %}

View File

@@ -0,0 +1,25 @@
{% comment %}
Adds child metadata to child modal in a description list element.
Fields are configured via _data/config-metadata.csv
{%- endcomment -%}
{%- assign fields = site.data.config-metadata | where_exp: 'item', 'item.display_name != nil' -%}
<div id="item-metadata">
<dl>
{% for f in fields %}{% if child[f.field] %}
<dt class="field">{{ f.display_name }}:</dt>
<dd class="field-value">
{% if f.browse_link == "true" %}
{% assign topics = child[f.field] | split: ";" %}
{% for t in topics %}
<a class="me-3" href="{{ t | strip | url_param_escape | prepend: '/browse.html#' | relative_url }}">{{ t | strip }}</a>
{% endfor %}
{% elsif f.external_link == "true" %}
<a href="{{ child[f.field] }}">{{ child[f.field] }}</a>
{% else %}
{{ child[f.field] | replace: '""','"' }}{% endif %}
</dd>
{% endif %}{% endfor %}
</dl>
</div>

View File

@@ -0,0 +1,27 @@
{% comment %}
Adds a panorama image viewer using Pannellum for child modals.
Default is set for equirectangular projection types.
https://pannellum.org/documentation/reference/
{%- endcomment -%}
<link rel="stylesheet" href="{{ site.lib-assets | default: '/assets/lib' | relative_url }}/pannellum/pannellum.css">
<div id="panorama" class="ratio ratio-4x3 my-4"></div>
<script src="{{ site.lib-assets | default: '/assets/lib' | relative_url }}/pannellum/pannellum.js"></script>
<script>
pannellum.viewer('panorama', {
"type": "equirectangular",
"panorama": "{{ child.object_location | relative_url }}",
"autoLoad": false,
/*
* Uncomment the next line to print the coordinates of mouse clicks
* to the browser's developer console, which makes it much easier
* to figure out where to place hot spots. Always remove it when
* finished, though.
*/
"hotSpotDebug": false,
"hotSpots": [
]
});
</script>

View File

@@ -0,0 +1,17 @@
{% comment %}
Adds a box to highlight rights information if child item has a "rights" or "rightsstatement" field.
{%- endcomment -%}
<div class="card mb-2">
<div class="card-header">Rights</div>
<div class="card-body">
<dl>
{% if child.rights %}<dt>Rights:</dt>
<dd>{{ child.rights }}</dd>{% endif %}
{% if child.rightsstatement %}<dt>Standardized Rights:</dt>
<dd><a href="{{ child.rightsstatement }}">{{ child.rightsstatement }}</a>
</dd>{% endif %}
</dl>
</div>
</div>

View File

@@ -0,0 +1,18 @@
{% comment %}
Adds an iframe video embed from a YouTube or Vimeo link given in child item's object_location.
{%- endcomment -%}
{% if child.object_location contains 'vimeo' %}
{% assign vimeo_id = child.object_location | split: '/' | last %}
<div class="ratio ratio-16x9">
<iframe title="video embed {{ child.title | escape }}" src="https://player.vimeo.com/video/{{ vimeo_id }}" allowfullscreen></iframe>
</div>
{%- elsif child.object_location contains 'youtu' -%}
{% assign youtube_id = child.object_location | split: '/' | last %}
{% if youtube_id contains 'v=' %}{% assign youtube_id = youtube_id | split: 'v=' | last | split: '&' | first %}
{% elsif youtube_id contains '?' %}{% assign youtube_id = youtube_id | split: '?' | first %}{% endif %}
<div class="ratio ratio-16x9">
<iframe title="video embed {{ child.title | escape }}" src="https://www.youtube-nocookie.com/embed/{{ youtube_id }}?enablejsapi=1&rel=0&modestbranding=1" allowfullscreen></iframe>
</div>
{% endif %}

View File

@@ -0,0 +1,12 @@
{% comment %}
Adds html video element with source given in child's object_location.
Sizing is controlled using Bootstrap "ratio" styles.
{%- endcomment -%}
<div class="ratio ratio-16x9">
<video {% if child.image_small %}poster="{{ child.image_small | relative_url }}" {% endif %}preload="metadata" controls>
<source src="{{ child.object_location | relative_url }}">
Your browser does not support the video tag.
</video>
</div>

View File

@@ -0,0 +1,14 @@
{% comment %}
Adds a basic citation box for the item with reference link to the item page.
{%- endcomment -%}
<div class="card">
<div class="card-header">Attribution</div>
<div class="card-body">
<dl>
<dt>Citation:</dt>
<dd>"{{ page.title }}", {{ site.title }}, {% if site.organization-name %}{{ site.organization-name }}, {% endif %}<a href="{{ page.url | absolute_url }}">{{ page.url | absolute_url }}</a></dd>
</dl>
</div>
</div>

View File

@@ -0,0 +1,34 @@
{% comment %}
Adds Item page button links, styled as a Bootstrap btn-group.
Features:
- View Transcript -- if the item has the field "object_transcript", this button is added along with a Bootstrap collapse containing the transcript content. If the value of "object_transcript" starts with objects/ it will look for the matching transcript file in the objects fold, otherwise it will use the value directly. Both will be rendered in Markdown.
- View on Timeline -- if the item has a "date" value, links to Timeline page.
- View on Map -- if item has "latitude" and "longitude" value, links to location on map.
- Download -- if the item has "object_location" value, adds a download button along with the item format, or if the value is a YouTube or Vimeo link adds a "View on" link.
{%- endcomment -%}
<div class="btn-group" role="group" aria-label="Item options">
{% if page.object_transcript %}<button class="btn btn-outline-primary" type="button" data-bs-toggle="collapse" data-bs-target="#collapseTranscript" aria-expanded="false" aria-controls="collapseTranscript">View Transcript</button>{% endif %}
{% if page.date %}{%- capture year -%}{% if page.date contains "-" %}{{ page.date | split: "-" | first }}{% elsif page.date contains "/" %}{{ page.date | split: "/" | last }}{% else %}{{ page.date }}{% endif %}{%- endcapture -%}
<a href="{{ year | strip | prepend: '/timeline.html#y' | relative_url }}" class="btn btn-outline-primary">View on Timeline</a>{% endif %}
{% if page.latitude and page.longitude %}
<a href="{{ '/map.html?location=' | append: page.latitude | append: ',' | append: page.longitude | append: '&marker=' | append: page.objectid | relative_url }}" class="btn btn-outline-primary">View on Map</a>{% endif %}
{% if page.object_location %}<a target="_blank" rel="noopener" href="{{ page.object_location | relative_url }}" class="btn btn-outline-primary">
{% if page.display_template == 'video' and page.object_location contains 'vimeo' %}View on Vimeo{% elsif page.display_template == 'video' and page.object_location contains 'youtu' %}View on YouTube{% elsif page.display_template == 'record'%}Link to Object{% else %}Download {{ page.format | split: '/' | last | default: page.display_template | upcase }}{% endif %}
</a>{% endif %}
</div>
{% if page.object_transcript %}
<div class="collapse mt-3" id="collapseTranscript">
<div class="card card-body text-start">
{% assign transcript_type = page.object_transcript | slice: 0,1 %}
{% if transcript_type == '/' %}
{% assign transcript_location = page.object_transcript | remove_first: '/' %}
{% assign transcript = site.pages | where: 'path', transcript_location | first %}
{{ transcript.content | markdownify }}
{% else %}
{{ page.object_transcript | markdownify }}
{% endif %}
</div>
</div>
{% endif %}

View File

@@ -0,0 +1,27 @@
{% comment %}
Internet Archive item embed.
Loads a book/pdf, video, or audio item from Internet Archive via their standard iframe embed.
The item's "objects_location" must be the full public URL to the object on IA. The item url looks something like:
book, https://archive.org/details/uidaho_gem_1903
video, https://archive.org/details/fluxusfireplace
audio, https://archive.org/details/aladore_1704_librivox
The embed works for books/pdfs, video, and audio--however, you will want to tweak the aspect ratio for different item types!
Options:
- "ratio" = use Bootstrap embed ratio options "21x9", "16x9", "4x3", or "1x1" to customize the responsive aspect ratio if not using height. 4x3 is default. (optional)
- "height" = set embed object height in px (rather than responsive size), width will be 100%, e.g. "800px" (optional)
- "style" = apply an arbitrary style to the div containing the embed. This is useful if you are trying to add a min height or custom aspect ratio. (optional)
- min height is useful for book items on mobile, e.g. "min-height: 500px;"
- custom aspect ratio may be useful for book items, e.g. "--bs-aspect-ratio: %115;"
- both e.g. "min-height: 500px;--bs-aspect-ratio: calc(3 / 4 * 100%);"
{% endcomment %}
{% assign archive_id = page.object_location | split: '/' | last %}
<div class="{% unless include.height %}ratio ratio-{{ include.ratio | default: '4x3' }}{% endunless %}"{% if include.style %} style="{{ include.style }}"{% endif %}>
<iframe title="item embed for {{ page.title | escape }}" src="https://archive.org/embed/{{ archive_id }}" {% if include.height %}class="w-100" height="{{ include.height }}"{% endif %} frameborder="0" webkitallowfullscreen="true" mozallowfullscreen="true" allowfullscreen></iframe>
</div>`

View File

@@ -0,0 +1,20 @@
{% comment %}
Embed Universal Viewer to load item from an IIIF manifest file, https://github.com/UniversalViewer/universalviewer
This include assumes that Item's object_location field is a relative link or direct url to a IIIF manifest json file. e.g. https://wellcomelibrary.org/iiif/b18035723/manifest
If you are using an external manifest url, you may encounter CORS policy error if the server hosting the manifest is not set up correctly--one workaround is to download the json file, add to your "objects" folder, and use a relative link, e.g. "objects/book-manifest1.json". You do not need the images, just the manifest file!
{% endcomment %}
<!-- add IIIF Universal Viewer assets from CDN -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/universalviewer@4.0.0/dist/uv.css"/>
<script src="https://cdn.jsdelivr.net/npm/universalviewer@4.0.0/dist/umd/UV.js"></script>
<!-- add div for viewer -->
<div class="uv" id="uv" style="width: 100%; height: 668px;"></div>
<script>
// initialize Universal Viewer
var uvOptions = {
manifest: {{ page.object_location | relative_url | jsonify }}
// add options here!
};
var iiif_viewer = UV.init("uv", uvOptions);
</script>

View File

@@ -0,0 +1,10 @@
{% comment %}
For image items, a zoomable, full screen gallery view is added using Spotlight gallery.
Ensure dependencies are added by including `gallery: true` in the layout front matter calling this include.
{%- endcomment -%}
<a id="{{ page.objectid }}" class="spotlight gallery-img" {% if page.object_location %}data-download="true"{% endif %} title="{{ page.title | escape }}" href="{{ page.object_location | default: page.image_small | relative_url }}">
<img src="{{ page.image_small | relative_url }}" alt="{{ page.image_alt_text | default: page.description | default: page.title | escape }}" class="img-fluid">
<div><small class="text-dark">Click to view full screen</small></div>
</a>

View File

@@ -0,0 +1,16 @@
{% comment %}
Add a thumbnail image or icon based on format for an item, with a object_location link (if available).
{% endcomment %}
{% if page.object_location %}<a href="{{ page.object_location | relative_url }}" target="_blank" rel="noopener">{% endif %}
{% if page.image_thumb or page.image_small %}
<img class="img-thumbnail" src="{{ page.image_small | default: page.image_thumb | relative_url }}" alt="{{ page.image_alt_text | default: page.description | default: page.title | escape }}">
{% else %}
<svg class="bi text-body" fill="currentColor" aria-hidden="true">
{%- assign icon_template = page.display_template | default: page.format -%}
<use xlink:href="{{ '/assets/css/cb-icons.svg' | relative_url }}#{% if icon_template contains 'image' %}icon-image{% elsif icon_template contains 'pdf' %}icon-pdf{% elsif icon_template contains 'audio' %}icon-audio{% elsif icon_template contains 'video' %}icon-video{% elsif icon_template contains 'record' %}icon-record{% else %}icon-default{% endif %}"/>
</svg>
<span class="visually-hidden">{{ page.title | escape }} - {{ page.format }}</span>
{% endif %}
{% if page.object_location %}</a>{% endif %}

View File

@@ -0,0 +1,25 @@
{% comment %}
Adds metadata to item pages in a description list element.
Fields are configured via _data/config-metadata.csv
{%- endcomment -%}
{%- assign fields = site.data.config-metadata | where_exp: 'item', 'item.display_name != nil' -%}
<div id="item-metadata">
<dl>
{% for f in fields %}{% if page[f.field] %}
<dt class="field">{{ f.display_name }}:</dt>
<dd class="field-value">
{% if f.browse_link == "true" %}
{% assign topics = page[f.field] | split: ";" %}
{% for t in topics %}
<a class="me-3" href="{{ t | strip | url_param_escape | prepend: ':' | prepend: f.field | prepend: '/browse.html#' | relative_url }}">{{ t | strip }}</a>
{% endfor %}
{% elsif f.external_link == "true" %}
<a href="{{ page[f.field] }}">{{ page[f.field] }}</a>
{% else %}
{{ page[f.field] | replace: '""','"' }}{% endif %}
</dd>
{% endif %}{% endfor %}
</dl>
</div>

View File

@@ -0,0 +1,59 @@
{% comment %}
Adds a Leaflet map featuring a single marker based on the item's lat long.
Options:
- "map-marker" = true/false, add a marker using the item's lat long and title (default true)
- "map-height" = height of the mini map in px (default 400px)
- "map-zoom" = provide a zoom level, default 10
- "map-link" = true/false, add a button link to the collection's default full map page (default false)
{% endcomment %}
<style>
#mini-map { height: {{ include.map-height | default: '400px' }}; z-index: 98; }
</style>
<div id="mini-map"></div>
{% if include.map-link == true %}
<a href="{{ '/map.html?location=' | append: page.latitude | append: ',' | append: page.longitude | append: '&marker=' | append: page.objectid | relative_url }}" class="btn btn-outline-primary my-3">View on Full Map</a>{% endif %}
<!-- load leaflet dependencies -->
<link rel="stylesheet" href="{{ site.lib-assets | default: '/assets/lib' | relative_url }}/leaflet/leaflet.css">
<link rel="stylesheet" href="{{ site.lib-assets | default: '/assets/lib' | relative_url }}/leaflet/leaflet.fullscreen.css">
<script src="{{ site.lib-assets | default: '/assets/lib' | relative_url }}/leaflet/leaflet.js"></script>
<script src="{{ site.lib-assets | default: '/assets/lib' | relative_url }}/leaflet/Leaflet.fullscreen.min.js"></script>
<script>
// initial start point
var mapCenter = [{{ page.latitude }}, {{ page.longitude }}];
var mapZoom = {{ include.map-zoom | default: 10 }};
/* init map, set center and zoom */
var map = L.map('mini-map').setView(mapCenter, mapZoom);
/* add map layer options */
var Esri_WorldStreetMap = L.tileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer/tile/{z}/{y}/{x}', {
attribution: 'Tiles &copy; Esri &mdash; Source: Esri, DeLorme, NAVTEQ, USGS, Intermap, iPC, NRCAN, Esri Japan, METI, Esri China (Hong Kong), Esri (Thailand), TomTom, 2012'
});
var Esri_NatGeoWorldMap = L.tileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/NatGeo_World_Map/MapServer/tile/{z}/{y}/{x}', {
attribution: 'Tiles &copy; Esri &mdash; National Geographic, Esri, DeLorme, NAVTEQ, UNEP-WCMC, USGS, NASA, ESA, METI, NRCAN, GEBCO, NOAA, iPC',
maxZoom: 16
});
var Esri_WorldImagery = L.tileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', {
attribution: 'Tiles &copy; Esri &mdash; Source: Esri, i-cubed, USDA, USGS, AEX, GeoEye, Getmapping, Aerogrid, IGN, IGP, UPR-EGP, and the GIS User Community'
});
/* add base map switcher */
var baseMaps = {
"Esri World StreetMap": Esri_WorldStreetMap,
"Esri National Geo": Esri_NatGeoWorldMap,
"Esri Imagery": Esri_WorldImagery
};
L.control.layers(baseMaps).addTo(map);
/* load base map */
Esri_WorldImagery.addTo(map);
/* add fullscreen control */
map.addControl(new L.Control.Fullscreen());
{% unless include.map-marker == false %}
/* add marker */
L.marker(mapCenter).addTo(map)
.bindPopup('{{ page.title | escape }}');{% endunless %}
</script>

View File

@@ -0,0 +1,27 @@
{% comment %}
Adds a panorama image viewer using Pannellum.
Default is set for equirectangular projection types.
https://pannellum.org/documentation/reference/
{%- endcomment -%}
<link rel="stylesheet" href="{{ site.lib-assets | default: '/assets/lib' | relative_url }}/pannellum/pannellum.css">
<div id="panorama" class="ratio ratio-4x3 my-4"></div>
<script src="{{ site.lib-assets | default: '/assets/lib' | relative_url }}/pannellum/pannellum.js"></script>
<script>
pannellum.viewer('panorama', {
"type": "equirectangular",
"panorama": "{{ page.object_location | relative_url }}",
"autoLoad": false,
/*
* Uncomment the next line to print the coordinates of mouse clicks
* to the browser's developer console, which makes it much easier
* to figure out where to place hot spots. Always remove it when
* finished, though.
*/
"hotSpotDebug": false,
"hotSpots": [
]
});
</script>

View File

@@ -0,0 +1,12 @@
{% comment %}
Embed PDF so that it directly loads on the item page.
Please note that embedding large PDFs will slow your user's accessing the page.
Size is controlled using Bootstrap Custom ratios, https://getbootstrap.com/docs/5.3/helpers/ratio/#custom-ratios
{% endcomment %}
<div class="ratio" style="--bs-aspect-ratio: 115%;">
<object title="PDF file of {{ page.title }}" data="{{ page.object_location | relative_url }}" type="application/pdf" width="100%" >
<p>The PDF is not rendering in your browser, please use the button below to download the PDF.</p>
</object>
</div>

View File

@@ -0,0 +1,17 @@
{% comment %}
Adds a box to highlight rights information if item has a "rights" or "rightsstatement" field.
{%- endcomment -%}
<div class="card">
<div class="card-header">Rights</div>
<div class="card-body">
<dl>
{% if page.rights %}<dt>Rights:</dt>
<dd>{{ page.rights }}</dd>{% endif %}
{% if page.rightsstatement %}<dt>Standardized Rights:</dt>
<dd><a href="{{ page.rightsstatement }}">{{ page.rightsstatement }}</a>
</dd>{% endif %}
</dl>
</div>
</div>

View File

@@ -0,0 +1,19 @@
{% comment %}
Adds an iframe video embed from a YouTube or Vimeo link given in object_location.
Sizing is controlled using Bootstrap "ratio" sizing.
{%- endcomment -%}
{% if page.object_location contains 'vimeo' %}
{% assign vimeo_id = page.object_location | split: '/' | last %}
<div class="ratio ratio-16x9">
<iframe title="video embed {{ page.title | escape }}" src="https://player.vimeo.com/video/{{ vimeo_id }}" allowfullscreen></iframe>
</div>
{%- elsif page.object_location contains 'youtu' -%}
{% assign youtube_id = page.object_location | split: '/' | last %}
{% if youtube_id contains 'v=' %}{% assign youtube_id = youtube_id | split: 'v=' | last | split: '&' | first %}
{% elsif youtube_id contains '?' %}{% assign youtube_id = youtube_id | split: '?' | first %}{% endif %}
<div class="ratio ratio-16x9">
<iframe title="video embed {{ page.title | escape }}" src="https://www.youtube-nocookie.com/embed/{{ youtube_id }}?rel=0&modestbranding=1" allowfullscreen></iframe>
</div>
{% endif %}

View File

@@ -0,0 +1,12 @@
{% comment %}
Adds html video element with source given in object_location.
Sizing is controlled using Bootstrap "ratio" styles.
{%- endcomment -%}
<div class="ratio ratio-16x9">
<video {% if page.image_small %}poster="{{ page.image_small | relative_url }}" {% endif %}preload="metadata" controls>
<source src="{{ page.object_location | relative_url }}">
Your browser does not support the video tag. Please <a href="{{ page.object_location | relative_url }}">download the video file</a>.
</video>
</div>