scaife-viewer / scaife-skeleton

front-end layout library for Scaife readers
https://scaife-viewer.org/
MIT License
2 stars 0 forks source link

Backport widgets from Explore Homer #60

Open jacobwegner opened 4 years ago

jacobwegner commented 4 years ago

In 2019, the Scaife Viewer team began working on two new sites to demonstrate enhancements to the Scaife Viewer platform, explorehomer.scaife-viewer.org and sv-mini.scaife-viewer.org.

scaife-widgets was a new NPM package introduced to help share widgets across these sites and with sites running v1 of the Scaife Vewer.

As the platform has continued to evolve, the team has decided that we may want to merge the reusable widgets back into the scaife-skeleton repository. We feel there may be additional packaging work to allow future sites to selectively install reusable components, but having the widgets live within scaife-skeleton will hopefully reduce friction in changing existing widgets or developing new ones.

At a high level, this is what we hope to achieve by the completion of the epic:

This should position us to then bring sv-mini up to parity with Explore Homer, and also allow us to do some additional work to further refine widget configuration / contracts for reuse across sites.

Related Trello cards

paltman commented 4 years ago

Some current thinking I'm having on how to structure things:

Packages

Under the @scaife-viewer npmjs org:

Reader Widget

This is a complex widget that is driven by display modes which are set by the Display Mode Widget. Display mode options are configured in the site's main getters, however, if none are defined, then the Reader Widget will default to the DefaultModeReader.vue.

Defining Display Modes

Each display mode will have it's own reader component that the ReaderWidget.vue hosts. These can be packaged and distributed independent of the scaife-viewer package. To configure, different display modes you'll want to add the DisplayModeWidget.vue to your skeleton and define the following in your main getters.js:

// The following reader components are imported from different sources and you
// customize for the needs of your site.  In this example, ImageModeReader and
// NamedEntitiesModeReader are imported from their own individual packages
// while the rest ship with and are imported from the scaife-viewer package.
const READER_COMPONENTS = {
  [DISPLAY_MODE_SENTENCE_ALIGNMENTS]: AlignmentsModeReader,
  [DISPLAY_MODE_FOLIO]: ImageModeReader,
  [DISPLAY_MODE_NAMED_ENTITIES]: NamedEntitiesModeReader,
  [DISPLAY_MODE_METRICAL]: MetricalModeReader,
  [DISPLAY_MODE_INTERLINEAR]: InterlinearModeReader,
  [DISPLAY_MODE_DEFAULT]: DefaultModeReader,
};

export default {
  readerComponent: state => {
    return READER_COMPONENTS[state.displayMode];
  },
  displayModes: state =>
    Object.keys(READER_COMPONENTS).map(key => ({
      ...READER_COMPONENTS[key].readerConfig,
      component: READER_COMPONENTS[key],
      mode: key,
      active: state.displayMode === key,
    })),
};

Mode Readers

These can pretty much be whatever you want component-wise. The only api is that they contain a static property called readerConfig that drives DisplayModeWidget.vue:

    readerConfig: {
      label: 'Default',
      layout: 'normal',
      textWidth: 'normal',
    },
paltman commented 4 years ago

I actually had forgotten about how we can inject arbitrary configuration into the $scaife root node, so instead of defining getters, we can just add a readerComponents key to the config:

const config = {
  entityMap: {
    accessToken:
      process.env.VUE_APP_ENTITY_MAP_ACCESS_TOKEN ||
      // eslint-disable-next-line max-len
      'pk.eyJ1IjoicGFsdG1hbiIsImEiOiJja2JpNDVpbmUwOGF1MnJwZm91c3VybDVrIn0.KRcXBGtiUWFXkp2uaE5LLw',
    mapStyle:
      process.env.VUE_APP_ENTITY_MAP_STYLE ||
      'mapbox://styles/paltman/ckbi4thqt156y1ijz5wldui14',
  },
  readerComponents: {
    [DISPLAY_MODE_SENTENCE_ALIGNMENTS]: AlignmentsModeReader,
    [DISPLAY_MODE_FOLIO]: ImageModeReader,
    [DISPLAY_MODE_NAMED_ENTITIES]: NamedEntitiesModeReader,
    [DISPLAY_MODE_METRICAL]: MetricalModeReader,
    [DISPLAY_MODE_INTERLINEAR]: InterlinearModeReader,
    [DISPLAY_MODE_DEFAULT]: DefaultModeReader,
  },
};

and then pull the readerComponent getter over into the ReaderWidget and the displayModes over into the DisplayModeWidget.

The state.displayMode and the setting of display mode might should move into the scaifeSkeleton part of the state tree, but not sure since it has only really to do with the reader. I find it similar to textSize and textWidth settings and they are in the scaifeWidgets tree. But in EH there is also a scaifeReader tree.

jacobwegner commented 4 years ago

@paltman Thanks for a great write up!

I'm + 1 on $scaife.config.readerComponents at the present time. In the near future, we might consider how "dynamic" the mode availability would be in as part of #62.

jacobwegner commented 4 years ago

I'm +0 on what we name stateTree; I see this being tied up in how we namespace / partition things as part of merging the scaife-widgets repo into this one.

In Scaife Viewer 1.0, we had different state trees for /reader and /library, but the "widget" distinction blurs that a bit, as we now have library widgets and possibly eventually the "View" at /library is a combination of main + sidebar widgets too.

So maybe state.scaifeViewer to simplify and then revisit when we need further partitioning?

jacobwegner commented 4 years ago

I think longer term, if we introduce more dynamic management of the skeleton by end users (multiple reader panes, splits, etc), some of the things like text size or text width or even display mode end up being reader-specific state. There is definitely some prior art in Digital Sira worth revisiting / refactoring we get to that point.