New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@thegetty/quire-11ty

Package Overview
Dependencies
Maintainers
0
Versions
45
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@thegetty/quire-11ty - npm Package Compare versions

Comparing version 1.0.0-rc.17 to 1.0.0-rc.18

_includes/components/lightbox/data.js

8

_includes/components/figure/audio/element.js

@@ -5,2 +5,3 @@ const { html } = require('~lib/common-tags')

const logger = chalkFactory('Figure Video')
/**

@@ -21,3 +22,3 @@ * Renders an embedded soundcloud audio player

const audioElements = {
soundcloud({ id, mediaId, mediaType }) {
soundcloud({ id, mediaId, mediaType, lazyLoading }) {
if (!mediaId) {

@@ -34,2 +35,3 @@ logger.error(`Cannot render SoundCloud component without 'media_id'. Check that figures data for id: ${id} has a valid 'media_id'`)

frameborder="no"
loading="${ lazyLoading ?? 'lazy' }"
height="166"

@@ -43,5 +45,5 @@ scrolling="no"

}
return function ({ id, mediaId, mediaType }) {
return audioElements[mediaType]({ id, mediaId, mediaType })
return function ({ id, mediaId, mediaType, lazyLoading }) {
return audioElements[mediaType]({ id, mediaId, mediaType, lazyLoading })
}
}

@@ -18,4 +18,4 @@ const { html } = require('~lib/common-tags')

return function({ caption, credit, id, label, mediaId, mediaType }) {
const audioElement = figureAudioElement({ id, mediaId, mediaType })
return function({ caption, credit, id, label, mediaId, mediaType, lazyLoading }) {
const audioElement = figureAudioElement({ id, mediaId, mediaType, lazyLoading })
const labelElement = figureLabel({ caption, id, label })

@@ -22,0 +22,0 @@ const captionElement = figureCaption({ caption, content: labelElement, credit })

@@ -16,4 +16,5 @@ /**

return async function (figure, options) {
const { alt, isCanvas, isImageService, isSequence, staticInlineFigureImage } = figure
return function (figure, options) {
const { alt, isCanvas, isImageService, isSequence, staticInlineFigureImage, lazyLoading } = figure
const { interactive, preset } = options

@@ -27,9 +28,9 @@ if (preset) {

if (!interactive && staticInlineFigureImage) {
return imageTag({ alt, src: staticInlineFigureImage, isStatic: !interactive })
return imageTag({ alt, src: staticInlineFigureImage, isStatic: !interactive, lazyLoading })
} else {
return await imageSequence(figure, options)
return imageSequence(figure, options)
}
case isCanvas:
if (!interactive && staticInlineFigureImage) {
return imageTag({ alt, src: staticInlineFigureImage, isStatic: !interactive })
return imageTag({ alt, src: staticInlineFigureImage, isStatic: !interactive, lazyLoading })
} else {

@@ -40,3 +41,3 @@ return canvasPanel(figure)

if (!interactive && staticInlineFigureImage) {
return imageTag({ alt, src: staticInlineFigureImage, isStatic: !interactive })
return imageTag({ alt, src: staticInlineFigureImage, isStatic: !interactive, lazyLoading })
} else {

@@ -43,0 +44,0 @@ return imageService(figure)

@@ -35,3 +35,3 @@ const { html } = require('~lib/common-tags')

*/
let imageElement = await figureImageElement(figure, { interactive: false })
let imageElement = figureImageElement(figure, { interactive: false })
imageElement = figureModalLink({ content: imageElement, id })

@@ -38,0 +38,0 @@

@@ -16,9 +16,14 @@ const { html } = require('~lib/common-tags')

return function ({ alt='', src='', isStatic=false }) {
return function ({ alt='', src='', isStatic=false, lazyLoading='lazy' }) {
const imageSrc = src.startsWith('http') || isStatic ? src : path.join(imageDir, src)
return html`
<img alt="${alt}" class="q-figure__image" src="${imageSrc}" />
<img alt="${alt}"
class="q-figure__image"
decoding="async"
loading="${lazyLoading}"
src="${imageSrc}"
/>
`
}
}
const path = require('path')
const { html } = require('~lib/common-tags')
module.exports = function(eleventyConfig) {
const renderWebcComponent = eleventyConfig.getFilter('renderWebcComponent')
const { assetDir } = eleventyConfig.globalData.config.figures
return async function({ id, sequences, startCanvasIndex }, { interactive=true }) {
return function({ id, sequences, startCanvasIndex }, { interactive=true }) {
const continuous = sequences[0].behavior.includes('continuous')
const itemUris = sequences[0].items.map(({ uri }) => uri).join(',')
const fileName = 'image-sequence.webc'
const includesDir = path.join(eleventyConfig.dir.input, eleventyConfig.dir.includes)
const componentPathname = __dirname.split(includesDir)[1]
const filePath = path.join(includesDir, componentPathname, fileName)
const reverse = sequences[0].viewingDirection === 'right-to-left'
// const filePath = path.join('_includes', 'components', 'figure', 'image', 'image-sequence.webc')
return await renderWebcComponent(filePath, {
'continuous': continuous,
'index': startCanvasIndex,
'items': itemUris,
'interactive': interactive,
'sequence-id': id,
'reverse': reverse
})
const reverse = sequences[0].viewingDirection === 'right-to-left'
// @todo Why does `html` not serialize boolean values to their string equivalent?
return html `
<q-image-sequence
continuous="${continuous ? 'true' : 'false'}"
index="${startCanvasIndex}"
interactive="${interactive ? 'true' : 'false'}"
items="${itemUris}"
reverse="${reverse ? 'true' : 'false'}"
sequence-id="${id}"
></q-image-sequence>
`
}
}

@@ -6,2 +6,3 @@ const { html } = require('~lib/common-tags')

const logger = chalkFactory('Figure Video')
/**

@@ -47,3 +48,3 @@ * Renders a native or embedded video player

},
vimeo({ id, mediaId, mediaType }) {
vimeo({ id, mediaId, mediaType, lazyLoading }) {
if (!mediaId) {

@@ -63,6 +64,7 @@ logger.error(`Cannot render Vimeo embed without 'media_id'. Check that figures data for id: ${id} has a valid 'media_id'`)

src="${embedUrl}"
loading="${ lazyLoading ?? 'lazy' }"
></iframe>
`
},
youtube({ id, mediaId, mediaType }) {
youtube({ id, mediaId, mediaType, lazyLoading }) {
if (!mediaId) {

@@ -82,2 +84,3 @@ logger.error(`Cannot render Youtube component without 'media_id'. Check that figures data for id: ${id} has a valid 'media_id'`)

src="${embedUrl}"
loading="${ lazyLoading ?? 'lazy' }"
></iframe>

@@ -93,2 +96,3 @@ `

poster,
lazyLoading,
src

@@ -103,4 +107,4 @@ }) {

return videoElements[mediaType]({ id, mediaId, mediaType, poster, src })
return videoElements[mediaType]({ id, mediaId, mediaType, poster, lazyLoading, src })
}
}

@@ -24,6 +24,7 @@ const { html } = require('~lib/common-tags')

poster,
src
src,
lazyLoading
}) {
const isEmbed = mediaType === 'vimeo' || mediaType === 'youtube'
const videoElement = figureVideoElement({ id, mediaId, mediaType, src, poster })
const videoElement = figureVideoElement({ id, mediaId, mediaType, src, poster, lazyLoading })
const labelElement = figureLabel({ caption, id, label })

@@ -30,0 +31,0 @@ const captionElement = figureCaption({ caption, content: labelElement, credit })

@@ -46,3 +46,4 @@ /**

lightbox: require('./lightbox/index.js'),
lightboxSlides: require('./lightbox/slides'),
lightboxData: require('./lightbox/data.js'),
lightboxStyles: require('./lightbox/styles.js'),
lightboxUI: require('./lightbox/ui'),

@@ -49,0 +50,0 @@ link: require('./link.js'),

const { html } = require('~lib/common-tags')
/**

@@ -11,3 +11,3 @@ * Lightbox Tag

module.exports = function (eleventyConfig, { page }) {
const lightboxSlides = eleventyConfig.getFilter('lightboxSlides')
const lightboxData = eleventyConfig.getFilter('lightboxData')
const lightboxUI = eleventyConfig.getFilter('lightboxUI')

@@ -20,3 +20,3 @@

<q-lightbox>
${await lightboxSlides(figures)}
${await lightboxData(figures)}
${lightboxUI(figures)}

@@ -23,0 +23,0 @@ </q-lightbox>

@@ -55,3 +55,3 @@ const { html } = require('~lib/common-tags')

return html`
<div class="q-lightbox-ui">
<div class="q-lightbox-ui" slot="ui">
<div class="q-lightbox-ui__zoom-and-fullscreen">

@@ -58,0 +58,0 @@ ${zoomButtons()}

@@ -10,4 +10,5 @@ const { html } = require('~lib/common-tags')

module.exports = function (eleventyConfig) {
const lightboxSlides = eleventyConfig.getFilter('lightboxSlides')
const lightboxStyles = eleventyConfig.getFilter('lightboxStyles')
const lightboxUI = eleventyConfig.getFilter('lightboxUI')
const lightboxData = eleventyConfig.getFilter('lightboxData')

@@ -20,3 +21,4 @@ return async function (figures) {

<q-lightbox>
${await lightboxSlides(figures)}
${lightboxStyles()}
${await lightboxData(figures)}
${lightboxUI(figures)}

@@ -23,0 +25,0 @@ </q-lightbox>

@@ -1,15 +0,19 @@

import { LitElement, html } from 'lit'
import { LitElement, html, render, unsafeCSS } from 'lit'
import { unsafeHTML } from 'lit-html/directives/unsafe-html.js'
/**
* Lightbox lit-element web component
* Lightbox lit-element web component markup and browser runtime
*
* This component renders image slides with navigation UI.
* It provides a default slot for passing markup to render:
* This component renders a custom element (q-lightbox) with slots for
* figures data, styles, and ui. On startup it loads its data, inserts its
* slides' markup, and manages a few internal properties and attributes during
* the component lifecycle.
*
* To display an element as a slide, provide it with a
* `data-lightbox-slide` attribute set to any value
* `data-lightbox-slide-id` attribute set to a unique id string
* Each slide (see `_lightboxSlide`) carries a
* `q-lightbox-slides__slide` class
* `id` attribute set to the figure's id
* `data-lightbox-current` (optional, any value) attribute lays out and displays the slide
* `data-lightbox-preload` (optional, any value) attribute lays out the slide without display
*
* This lightbox provides access to controls with the following data attributes:
* This lightbox expects its UI slot to have elements for a few controls:
* - `data-lightbox-fullscreen` triggers fullscreen on click and indicates status

@@ -19,13 +23,33 @@ * - `data-lightbox-next` triggers rendering of next slide on click

*
* It dynamically updates the content of elements with these data attributes:
* It dynamically updates the content of its UI labels with these data attributes:
* - `data-lightbox-counter-current` displays the current slide index
* - `data-lightbox-counter-total` displays total number of slides
*
* For each figure's data:
* - Aligned to an internal data representation that eases slide logic and markup
* - Inserted into slide markup with the appropriate slot and added to the lightbox
*/
class Lightbox extends LitElement {
static properties = {
currentId: { attribute: 'current-id', type: String },
preloadNextId: { attribute: 'preload-next-id', type: String },
preloadPrevId: { attribute: 'preload-prev-id', type: String },
}
setupStyles() {
let styleElement = this.querySelector('style[slot="lightbox-styles"]')
if (styleElement && styleElement.sheet) {
this.adoptedStyleSheets = [ styleElement.sheet ]
}
}
constructor() {
super()
// NB: UI controls check this.slides so load figures first
this.setupStyles()
this.setupFiguresData()
this.setupFullscreenButton()

@@ -57,3 +81,3 @@ this.setupNavigationButtons()

get slides() {
return this.querySelectorAll('[data-lightbox-slide]')
return this.querySelectorAll('.q-lightbox-slides__slide')
}

@@ -64,3 +88,3 @@

.from(this.slides)
.map((slide) => slide.dataset.lightboxSlideId)
.map((slide) => slide.id)
}

@@ -127,2 +151,83 @@

/**
* @function _alignSlideData
* @param {Object} figure - data for a quire figure
* @return {Object} - data w/ a few useful props added
*/
_alignSlideData(figure) {
const {
aspect_ratio: aspectRatio='widescreen',
caption,
credit,
id,
isSequence,
label,
mediaType
} = figure
const isAudio = mediaType === 'soundcloud'
const isVideo = mediaType === 'video' || mediaType === 'vimeo' || mediaType === 'youtube'
return { ...figure, isAudio, isVideo, aspectRatio }
}
/**
* @function _lightboxSlide
* @param {Object} figure - slide data
* @return {Lit.html} - Lit HTML component
*
* Composites slide data into the slide markup and injects pre-serialized figure elements
**/
_lightboxSlide(figure) {
const { id,
mediaType,
figureElementContent,
annotationsElementContent,
aspectRatio,
isVideo,
isAudio,
label,
labelHtml,
caption,
captionHtml,
credit,
creditHtml
} = figure
const slideMediaClass = `q-lightbox-slides__element--${mediaType}`
const videoClass = isVideo ? `q-lightbox-slides__element--video q-lightbox-slides__element--${aspectRatio}` : ''
const audioClass = isAudio ? 'q-lightbox-slides__element--audio' : ''
return html`<div class="q-lightbox-slides__slide" slot="slides" id="${id}">
<div class="q-lightbox-slides__element ${slideMediaClass} ${videoClass} ${audioClass}">
${unsafeHTML(figureElementContent)}
</div>
<div class="q-figure-slides__slide-ui">
<div class="q-lightbox-slides__caption ${ label || caption || credit ? '' : 'is-hidden' }">
<span class="q-lightbox-slides__caption-label ${ label ? '' : 'is-hidden' }">${unsafeHTML(labelHtml)}</span>
<span class="q-lightbox-slides__caption-content ${ caption || credit ? '' : 'is-hidden' }">${captionHtml ? unsafeHTML(captionHtml) : ''} ${creditHtml ? unsafeHTML(creditHtml) : ''}</span>
</div>
${unsafeHTML(annotationsElementContent ?? '')}
</div>
</div>`
}
setupFiguresData() {
const figuresData = this.querySelector('script[type="application/json"]')
const figures = JSON.parse(figuresData.innerHTML)
this.figures = figures
figures.forEach( fig => {
console.log('Rendering',fig.id)
const dat = this._alignSlideData(fig)
// NB: This is done in lightDOM *not* shadowDOM
let slideElement = document.createElement('template')
render(this._lightboxSlide(dat),slideElement.content)
const slide = slideElement.content.cloneNode(true)
this.appendChild(slide)
})
}
setupFullscreenButton() {

@@ -185,5 +290,14 @@ if (!this.fullscreenButton) return

this.slides.forEach((slide) => {
if (slide.dataset.lightboxSlideId !== this.currentId)
if (slide.id !== this.currentId) {
delete slide.dataset.lightboxCurrent
}
if ([this.preloadNextId,this.preloadPrevId].includes(slide.id)) {
slide.dataset.lightboxPreload = true
} else {
delete slide.dataset.lightboxPreload
}
})
this.currentSlide.dataset.lightboxCurrent = true

@@ -199,8 +313,16 @@ }

this.currentId = this.slideIds[this.currentSlideIndex]
this.preloadNextId = this.currentSlideIndex + 1 < this.slideIds.length ? this.slideIds[this.currentSlideIndex + 1] : undefined
this.preloadPrevId = this.currentSlideIndex - 1 >= 0 ? this.slideIds[this.currentSlideIndex - 1] : undefined
this.updateCurrentSlideElement()
this.updateCounterElements()
// NB: `lightbox-styles` are dynamically loaded by the constructor
return html`
<div class="q-lightbox">
<slot></slot>
<slot name="lightbox-styles"></slot>
<slot name="data"></slot>
<div class="q-lightbox-slides">
<slot name="slides"></slot>
</div>
<slot name="ui"></slot>
</div>

@@ -207,0 +329,0 @@ `

## `<q-lightbox>` lightbox web component
This component renders image slides with navigation UI. It provides a default slot for passing markup to render.
This directory contains the javascript boilerplate for producing the q-lightbox web component template and its interactivity. See also `_includes/components/lightbox` and `_incldues/components/modal` for usage.
## Architecture
`q-lightbox` provides a lightbox for quire figures via a [web component](), a technology for style and code encapsulation for UI components on the web.
The javscript here (via Lit boilerplate) produces the `q-lightbox` <template> and the lifecycle methods for managing data in the component when it first loads.
### Markup
HTML markup for q-lightbox is generated in the `render()` function below, it has a few web component `slot` elements to ease compositing its contents. All are required for the lightbox to work:
- `slot="data"` should be a `<script>` tag containing the figures data. It is loaded on component startup.
- `slot="ui"` should be a `<div>` containing the lightbox UI
- `slot="slides"` contains slides that are dynamically generated after data load (or could be provided in markup as well).
- `slot="styles"` should contain a `<style>` tag with the styles for this lightbox.
### Styling
Styles for web components are strongly encapsulated, so inner elements (eg, the element expected to return from a selector like `q-lightbox > div`) are only responsive to the web component's stylesheet.
*Note this is also true from a javascript perspective!* That is, `document.querySelector('q-lightbox').querySelector('div')` would be the only correct way to query a `div` within a `q-lightbox` web component.
The effect of this is that q-lightbox needs to contain the styles for all its inner componentry, and must contain them as CSS.
#### Some trickery
Because only 11ty has build-time access to the sass stylesheets, `_includes/components/lightbox/styles.js` compiles the lightbox stylesheet at build time and inserts it into the component, where it loaded on component startup because WC styles must either be provided in the template or dynamically and Lit is entirely in runtime/browserspace.
### Interactivity
To display a child element of the slot as a slide, provide it with a `data-lightbox-slide` attribute set to anything and a `data-lightbox-slide-id`
set to a unique string (in our case, the figure id). **Note:** the value of `data-lightbox-slide-id` only needs to be unique among other slot children with `data-lightbox-slide` set
set to a unique string (in our case, the figure id). **Note:** the value of `id` only needs to be unique among other slot children with `data-lightbox-slide` set

@@ -8,0 +34,0 @@ This lightbox provides access to controls with the following data attributes:

@@ -29,3 +29,4 @@ const filters = require('./filters')

eleventyConfig.addCollection('temp', function (collectionApi) {
const eleventyCollections = collectionApi.getAll()[0].data.collections
const allCollections = collectionApi.getAll()
const eleventyCollections = allCollections.length > 0 ? collectionApi.getAll()[0].data.collections : {}
Object.assign(collections, eleventyCollections)

@@ -32,0 +33,0 @@ return []

@@ -29,3 +29,3 @@ const chalkFactory = require('~lib/chalk')

constructor(figure, data) {
const { annotationCount, iiifConfig, outputDir, outputFormat, zoom } = figure
const { annotationCount, iiifConfig, outputDir, outputFormat, src: figureSrc, zoom } = figure
const { baseURI, tilesDirName } = iiifConfig

@@ -65,3 +65,3 @@ const { label, region, selected, src, text } = data

&& outputFormat === '.jpg'
&& (annotationCount === 0 || src === figure.src)
&& (annotationCount === 0 || src === figureSrc)
const info = () => {

@@ -103,5 +103,5 @@ if (!isImageService) return

this.text = text
this.type = figure.src || region || text ? 'annotation' : 'choice'
this.type = figureSrc || region || text ? 'annotation' : 'choice'
this.uri = uri()
}
}

@@ -92,3 +92,2 @@ const chalkFactory = require('~lib/chalk')

this.annotationCount = data.annotations ? data.annotations.length : 0
this.annotationFactory = new AnnotationFactory(this)
this.canvasId = canvasId()

@@ -108,3 +107,2 @@ this.data = data

this.processImage = imageProcessor
this.sequenceFactory = new SequenceFactory(this)
this.src = src

@@ -116,2 +114,6 @@ /**

this.zoom = isSequence(data) ? false : zoom
// NB: *Factory depend on props of `this` so Object.assign() breaks circularity
this.annotationFactory = new AnnotationFactory(Object.assign({},this))
this.sequenceFactory = new SequenceFactory(Object.assign({},this))
}

@@ -118,0 +120,0 @@

@@ -16,2 +16,4 @@ const Ajv = require('ajv')

*
* NB: This is also imported by CLI commands
*
*/

@@ -18,0 +20,0 @@ const validateUserConfig = (type, data, schemas = { config: configSchema }) => {

@@ -6,2 +6,4 @@ const chalkFactory = require('~lib/chalk')

const FETCH_PRIORITY_THRESHOLD = 2
/**

@@ -48,2 +50,6 @@ * Render an HTML <figure> element

// Pass a lazyload parameter for use in downstream components
const position = ( this.page.figures ?? [] ).length - 1
const lazyLoading = position < FETCH_PRIORITY_THRESHOLD ? 'eager' : 'lazy'
const { mediaType } = figure

@@ -68,3 +74,3 @@

<figure id="${slugify(id)}" class="${['q-figure', 'q-figure--' + mediaType, ...classes].join(' ')}">
${await component(figure)}
${await component({...figure,lazyLoading})}
</figure>

@@ -71,0 +77,0 @@ `

@@ -15,2 +15,12 @@ # Changelog

## [1.0.0-rc.18]
### Changed
- Performance improvments for images:
- Refactor `figure` subcomponent composition using named `slot` elements for data, ui, slides, and styles
- Refactor `lightbox` components to generate slides dynamically from JSON data
- Compiles `lightbox` styles and inserts them in the component's style slot at publication build-time
- Refactors `image-sequence` as a Lit web component: `q-image-sequence`
## [1.0.0-rc.17]

@@ -17,0 +27,0 @@

@@ -29,3 +29,3 @@ import { intersectionObserverFactory } from './intersection-observer-factory'

const canvasPanel = element.querySelector('canvas-panel')
const imageSequence = element.querySelector('image-sequence')
const imageSequence = element.querySelector('q-image-sequence')
const imageService = element.querySelector('image-service')

@@ -81,3 +81,3 @@

const figureSelector = `#${figureId}`
const slideSelector = `[data-lightbox-slide-id="${figureId}"]`
const slideSelector = `[slot="slides"][id="${figureId}"]`
const figure = document.querySelector(figureSelector)

@@ -90,3 +90,3 @@ const figureSlide = document.querySelector(slideSelector)

const inputs = document.querySelectorAll(`#${figureId} .annotations-ui__input, [data-lightbox-slide-id="${figureId}"] .annotations-ui__input`)
const inputs = document.querySelectorAll(`#${figureId} .annotations-ui__input, [slot="slides"][id="${figureId}"] .annotations-ui__input`)
const annotations = [...inputs].map((input) => {

@@ -287,3 +287,3 @@ const id = input.getAttribute('data-annotation-id')

const update = (id, data) => {
const webComponents = document.querySelectorAll(`canvas-panel[canvas-id="${id}"], image-service[src="${id}"], image-sequence[sequence-id="${id}"]`)
const webComponents = document.querySelectorAll(`canvas-panel[canvas-id="${id}"], image-service[src="${id}"], q-image-sequence[sequence-id="${id}"]`)
if (!webComponents.length) {

@@ -296,3 +296,3 @@ console.error(`Failed to call update on canvas panel or image-service component with id ${id}. Element does not exist.`)

const isImageSequence = element.tagName.toLowerCase() === 'image-sequence'
const isImageSequence = element.tagName.toLowerCase() === 'q-image-sequence'

@@ -299,0 +299,0 @@ if (isImageSequence) {

{
"name": "@thegetty/quire-11ty",
"version": "1.0.0-rc.17",
"version": "1.0.0-rc.18",
"description": "Quire 11ty static site generator",

@@ -5,0 +5,0 @@ "keywords": [

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc