Utstillingsløsning

Nansen

Eksisterende system

(utelukker "spesialistsystem")

Hva er galt med         ?

  • Kan brukes headless... men fokuserer på tekst i ren html
  • Mange plugins... men mange går i beina på hverandre
    • Vanskelig å vite hvilke sideeffekter som kommer med
    • Ukjent utviklingsprosess
  • Driftes på IT... men vi har lite kontroll
  • Kommer med en milliard themes... men unødvendig vanskelig å lage egne

 

spesial.w.uib.no ble, slik jeg ser det, beholdt fordi vi ikke hadde tilsvarende funksjonalitet i Protégé/Marcus. Planen har alltid vært å migrere innhold.

Hva er galt med         ?

  • Kan brukes headless... men PHP gjør at DU må håndtere to språk for én side
  • Mange modules... men mange går i beina på hverandre
    • Vanskelig å vite hvilke sideeffekter som kommer med
    • Ukjent utviklingsprosess
  • Driftes på IT... men vi har lite kontroll
  • Kommer med en milliard themes... men unødvendig vanskelig å lage egne

Hva er galt med         ?

  • Kan brukes headless... men PHP gjør at DU må håndtere to språk for én side
  • Mange modules... men mange går i beina på hverandre
    • Vanskelig å vite hvilke sideeffekter som kommer med
    • Ukjent utviklingsprosess
  • Tilpassbar datamodel med domain-range... men håndhever den ikke
  • Laget for nettutstillinger... men unødvendig dersom vi allerede må lage en løsning for Marcus?

Hva er galt med             ?

  • Er en frontend over en "headless CMS"... men PHP gjør at DU må håndtere to språk for én side
  • PHP er serverside... må skrive JS for klienten
  • Query-based template-engine...  men håpløst utdatert

Kort sagt

  • De har et gammelt driftskonsept

Et annet "systemlandskap"?

Birgitta

DEV

PROD

build
preview
data
build
trigger

ETL BUS

marcus.uib.no/
exhibition/nansen

npm i -g @sanity/cli
sanity init
project

Sanity

@seidhr/sanity-template-muna

marcus-monorepo

???

/api

/studio

/shared/ui-components

Felles git repositorie med felles komponenter som kan gjenbrukes og oppdateres på tvers av ulike frontends

/exhibitions

/

/search

Javascript

Hvilket rammeverk?

Basics

/pages
/pages/id
/pages/id/index.js
/pages/id/[id].js
/pages/actor/index.js
/pages/actor/[id].js
/pages/blog/index.js
/pages/blog/[id].js
...
/pages/api/manifest/index.js
/pages/api/manifest/[id].js
...
/components
/components/Footer.js
/components/Header.js
/components/Nav.js
/components/Sections
/components/Sections/index.js
/components/Sections/Hero.js

Next folder structure under pages equals URI paths

Components breaks the UI into smaller parts that can be reused on any page or on other sites if shared as a NPM package

API endpoints created in same manner as pages

Concepts.js

...
import {getAllConcepts} from '../../lib/api'
import Layout from '../../components/Layout'
import Header from '../../components/Header'
import {Container, List, ListItem} from '@chakra-ui/react'
import Link from '../../components/Link'

export default function Concepts({data, preview}) {
  return (
    <>
      <Layout preview={preview}>
        <Head>
          <title>{CMS_NAME}</title>
        </Head>

        <Header menu={data.defaultNavMenu} />

        <Container maxW="xl">
          {data.items && (
            <List>
              {data.items
                .filter((item) => item.count > 0)
                .map((item) => (
                  <ListItem key={item._id}>
                    <Link href={`/id/${item._id}`}>{item.label.nor}</Link> <span>{item.count}</span>
                  </ListItem>
                ))}
            </List>
          )}
        </Container>
      </Layout>
    </>
  )
}

export async function getStaticProps({preview = false}) {
  const data = await getAllConcepts(preview)
  return {
    props: {data, preview},
  }
}

Component

import dynamic from 'next/dynamic'
import {Grid, Container, Box, Center, Heading, Text} from '@chakra-ui/react'
import PortableTextBlock from '../PortableTextBlock'

const MiradorWithNoSSR = dynamic(() => import('../Mirador'), {ssr: false})

export default function SingleObject(props) {
  if (!props) { return null }

  return (
    <Container maxW="xl" centerContent>
      <Grid
        w="full"
        p={5}
        gridGap={5}
        alignContent="start"
        gridTemplateAreas={{xl: '"image image metadata"', base: '"image" "metadata"'}}
        gridTemplateColumns={{xl: '6fr 6fr 2fr', base: '100%'}}
      >
        <Box gridArea="metadata">
          <Heading fontSize="sm" mb={1} color="gray.600">
            {props.heading}
          </Heading>

          {props?.description && (
            <Box fontSize="xs" fontFamily="Montserrat" fontWeight="200">
              <PortableTextBlock blocks={props.description} />
            </Box>
          )}
        </Box>

        {props?.item.manifest && (
          <Box gridArea="image">
            <MiradorWithNoSSR manifest={[props.item.manifest]} />
          </Box>
        )}
      </Grid>
    </Container>
  )
}

/blog

data: Wordpress
func: getStaticProps

/

data: Sanity
func: getStaticProps

/id/*

data: API ? API : Sparql
func: getServerSideProps

/exhibition

data: Sanity
func: getStaticProps
export async function getStaticProps({preview = false}) {
  const data = await getFrontpage(preview)
  return {
    props: {data, preview},
  }
}
export async function getStaticProps({preview = false}) {
  const data = await getWpBlogPosts(preview)
  return {
    props: {data, preview},
  }
}
export async function getStaticProps({preview = false}) {
  const data = await getPage(preview)
  return {
    props: {data, preview},
  }
}
export async function getServerSideProps({preview = false}) {
  const data = await getObject(preview)
  return {
    props: {data, preview},
  }
}

//marcus.uib.no/

Fetching data

export async function getAllActors() {
  const data = await client.fetch(`{
    "items": *[_type in ["actor", "group"]] | order(label, desc){ 
      "id": _id,
      _type,
      label,
      hasType[]-> {
        _id,
        label
      },
      mainRepresentation,
      "count": count(*[references(^._id)]),
    },
    ${defaultNavMenu}
  }`)
  return data
}
{
  @id: "0cdad732-e877-4609-b61a-7e780a9a9bba",
  @type: "MadeObject",
  hasType: [
  	{
      @id: "bf229013-1d51-4666-8219-3ed7edcae4c1",
      @type: "Type",
      label: {
      	no: "Manuskript",
        en: "Manuscript",
      }
    }
  ],
  identifidBy: [
    {
      @id: "99d104c5-e569-4632-9d39-323e9b64c041",
      @type: "Identifier",
      content: "ubb-ms-0149-01",
    }
  ],
  title: "Håndskrevet bok, bestående av tre innførte bøker.",
  hasThumbnail: {
    @type: "http://www.w3.org/2001/XMLSchema#anyuri",
    value: "https://api.ub.uib.no/iiif/image/b0383825-9151-4c34-accb-98e9e7651fa4",
  },
  subjectOfManifest: "https://api.ub.uib.no/iiif/manifest/0cdad732-e877-4609-b61a-7e780a9a9bba",
  subject: [{
    @id: "8749a213-48ba-441d-afbe-df0a63b0518d"
  }],
  description: `
    En liden nyttig Eungeliske Epitoliske Haandbog 
    af Rasmus Suendsøn, Ottense (Odense).
  `
}
{
  @id: "55d8206d-6d38-46e6-86a3-fda8b44b8ea0",
  @type: "linguisticObject",
  hasType: [
    {
      @id: "58e6136e-4f1f-48a5-ba56-4267c6db58e6",
      @type: "Type",
      label: {
      	no: "Kort beskrivelse",
        en: "Short description",
      }
    }
  ],
  title: "Denne boken er for lang!",
  refersTo: { 
    @id: "marcus:0cdad732-e877-4609-b61a-7e780a9a9bba"
  },
  content: "Åh, himmel og hav! Denne bok tar jo aldri slutt!",
}

Sanity JSON to JSON-LD

function toJSONids(arr) {
  return arr.map((o) =>
    rename(o, function (key) {
      if (key === "_id" || key === "_ref" || key === "_key") return "id";
      return key;
    })
  );
}

// All PortableText must be converted to html
const pt2html = madeObjects.map((o) => 
  ({
  ...o,
    referredToBy: o.referredToBy.map(b => ({
      ...b,
      body: blocksToHtml({
        blocks: b.body,
        serializers: serializers,
      }) 
    }))
  })
)
const fixIDs = toJSONids(pt2html)
const removedRev = fixIDs.map(o => {return removeKey(o, "_rev")});
const removeUnderscore = removedRev.map((o) =>
                                        rename(o, function (key) {
  if (key.startsWith('_')) {
    return key.substring(1)
  };
  return key;
})
                                       )
const result = filterObject(removeUnderscore, "type", "reference");

const json = {
  ...context,
  "@graph": [...result],
};

API

Document api structure before coding

Infrastructure scrible

Utstillingsløsning

By Tarje Lavik

Utstillingsløsning

  • 282