Skip to content

Commit

Permalink
Merge pull request #10 from hypermedia-app/pointer-refactor
Browse files Browse the repository at this point in the history
Next milestone: solid refactoring
  • Loading branch information
tpluscode authored Aug 14, 2021
2 parents b6af64c + abefa91 commit 6d73bc9
Show file tree
Hide file tree
Showing 66 changed files with 2,586 additions and 1,145 deletions.
5 changes: 5 additions & 0 deletions .changeset/brave-zebras-sing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@hydrofoil/roadshow": patch
---

Ability to select multi-viewer to render multiple properties
5 changes: 5 additions & 0 deletions .changeset/nice-books-fetch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@hydrofoil/roadshow": minor
---

Redesign the state and rendering process
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ dist/
*.js
*.d.ts
*.map
coverage/
5 changes: 5 additions & 0 deletions apps/storybook/lib/ns.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import namespace from '@rdf-esm/namespace'

export const hex = namespace('https://w3id.org/hydra/extension#')
export const ex = namespace('https://example.com/')
export const wbo = namespace('https://wikibus.org/ontology#')
1 change: 1 addition & 0 deletions apps/storybook/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"@rdf-esm/dataset": "^0.5.1",
"@rdf-esm/formats-common": "^0.5",
"@rdf-esm/namespace": "^0.5",
"@rdf-esm/term-map": "^0.5.1",
"@rdf-esm/term-set": "^0.5",
"@rdfine/hydra": "^0.7.1",
"@rdfine/schema": "^0.6.5",
Expand Down
59 changes: 31 additions & 28 deletions apps/storybook/resources/hydra-collection.ttl
Original file line number Diff line number Diff line change
Expand Up @@ -4,34 +4,37 @@ PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
@prefix schema: <http://schema.org/> .

<> a hydra:Collection ;
hydra:member
[
a schema:Person ;
schema:familyName "Doe" ;
schema:givenName "John" ;
schema:telephone "123456789" ;
schema:image [
a schema:ImageObject ;
schema:contentUrl <https://www.placecage.com/320/240> ;
schema:caption "John's profile image" ;
]
], [
a schema:Person ;
schema:familyName "Doe" ;
schema:givenName "Jane" ;
schema:telephone "555666777" ;
schema:image
[
a schema:ImageObject ;
schema:contentUrl <https://placeimg.com/320/240/face> ;
schema:caption "Jane's profile image" ;
]
] ;
hydra:manages
[
hydra:property rdf:type ;
hydra:object schema:Person ;
] ;
hydra:title "Addressbook"@en, "Książka adresowa"@pl ;
hydra:member
[
a schema:Person ;
schema:familyName "Doe" ;
schema:givenName "John" ;
schema:telephone "123456789" ;
schema:image
[
a schema:ImageObject ;
schema:contentUrl <https://www.placecage.com/320/240> ;
schema:caption "John's profile image" ;
]
],
[
a schema:Person ;
schema:familyName "Doe" ;
schema:givenName "Jane" ;
schema:telephone "555666777" ;
schema:image
[
a schema:ImageObject ;
schema:contentUrl <https://placeimg.com/320/240/face> ;
schema:caption "Jane's profile image" ;
]
] ;
hydra:manages
[
hydra:property rdf:type ;
hydra:object schema:Person ;
] ;
hydra:view
[
a hydra:PartialCollectionView ;
Expand Down
25 changes: 25 additions & 0 deletions apps/storybook/shapes/hydra-PartialCollectionView.ttl
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
PREFIX dash: <http://datashapes.org/dash#>
PREFIX hydra: <http://www.w3.org/ns/hydra/core#>
PREFIX sh: <http://www.w3.org/ns/shacl#>

<>
a sh:NodeShape ;
sh:targetClass hydra:PartialCollectionView ;
sh:property
[
sh:path hydra:first ;
sh:order 0 ;
],
[
sh:path hydra:previous ;
sh:order 1 ;
],
[
sh:path hydra:next ;
sh:order 2 ;
],
[
sh:path hydra:last ;
sh:order 3 ;
]
.
14 changes: 13 additions & 1 deletion apps/storybook/shapes/hydra-collection.ttl
Original file line number Diff line number Diff line change
@@ -1,12 +1,24 @@
PREFIX dash: <http://datashapes.org/dash#>
PREFIX hydra: <http://www.w3.org/ns/hydra/core#>
PREFIX sh: <http://www.w3.org/ns/shacl#>
PREFIX hex: <https://w3id.org/hydra/extension#>
prefix ex: <https://example.com/>

<>
sh:targetClass hydra:Collection ;
sh:property
[
sh:path hydra:title ;
sh:order 0 ;
dash:viewer ex:LocalLabelViewer ;
],
[
sh:path hydra:member ;
dash:viewer dash:HydraMemberViewer ;
dash:viewer hex:MembersViewer ;
sh:order 1 ;
],
[
sh:path hydra:view ;
sh:order 2 ;
] ;
.
205 changes: 30 additions & 175 deletions apps/storybook/stories/HydraCollection.stories.ts
Original file line number Diff line number Diff line change
@@ -1,207 +1,62 @@
import { html } from 'lit'
import { MultiRenderer, Renderer, ViewerMatchInit } from '@hydrofoil/roadshow'
import { MultiRenderer, Renderer, ViewerMatcher } from '@hydrofoil/roadshow'
import '@hydrofoil/roadshow/roadshow-view'
import { findNodes } from 'clownface-shacl-path'
import { hydra, sh, rdf, schema, dash, rdfs } from '@tpluscode/rdf-ns-builders'
import { fromPointer } from '@rdfine/shacl/lib/NodeShape'
import { NamedNode } from 'rdf-js'
import { hydra, rdf, schema } from '@tpluscode/rdf-ns-builders/strict'
import type { MultiPointer } from 'clownface'
import type { Literal } from '@rdfjs/types'
import { template } from '../lib/template'
import addressBook, { QuadArrayFactory } from '../resources/hydra-collection.ttl'
import hydraCollectionShape from '../shapes/hydra-collection.ttl'
import hydraPartialCollectionViewShape from '../shapes/hydra-PartialCollectionView.ttl'
import schemaPerson from '../shapes/schema-person.ttl'
import { runFactory } from '../resources/runFactory'

const collectionViewer: ViewerMatchInit = {
viewer: dash.HydraCollectionViewer,
match({ resource }) {
return resource.has(rdf.type, hydra.Collection).terms.length ? 50 : 0
},
}

const pagerViewer: ViewerMatchInit = {
viewer: dash.HydraPartialCollectionViewViewer,
match({ resource }) {
return resource.has(rdf.type, hydra.PartialCollectionView).terms.length ? 50 : 0
},
}

const localizedLabelViewer: ViewerMatchInit = {
viewer: dash.LocalLabelViewer,
matchMulti({ state }) {
return state.path?.term?.equals(rdfs.label) ? 1 : 0
},
}

const localizedLabel: MultiRenderer<any> = {
viewer: dash.LocalLabelViewer,
render(resources: MultiPointer<Literal>) {
const arr = resources.toArray()
const label = arr.find(r => r.term.language === this.params.language) || arr.find(r => r.term.language === 'en')

return label ? html`${this.show({ property: rdfs.label, resource: label, viewer: dash.LiteralViewer })}` : ''
},
}

const tableView: Renderer = {
viewer: dash.HydraCollectionViewer,
render(collection, shape) {
const memberTypes = collection
.out(hydra.manages)
.has(hydra.property, rdf.type)
.out(hydra.object)

const memberShape = this.shapes.shapes
.find(shape => shape.pointer.has(sh.targetClass, memberTypes).terms.length)
const memberPropertyShape = shape?.property.find(({ pointer }) => hydra.member.equals(pointer.out(sh.path).term))
const viewPropertyShape = shape?.property.find(({ pointer }) => hydra.view.equals(pointer.out(sh.path).term))

return html`<table>
<thead>
<tr>
${memberShape?.property.filter(p => !p.hidden).map(prop => html`<td>${prop.name}</td>`)}
</tr>
</thead>
<tbody>
${collection.out(hydra.member).map(resource => html`<tr>${this.show({
resource,
shape: memberShape,
property: memberPropertyShape || hydra.member,
})}</tr>`)}
</tbody>
</table>
${collection.out(hydra.view).map(view => this.show({
resource: view,
property: viewPropertyShape || hydra.view,
}))}`
},
}

const pagerView: Renderer = {
viewer: dash.HydraPartialCollectionViewViewer,
render(resource) {
const link = (property: NamedNode) => {
const page = resource.out(property).toArray()[0]
return !page
? ''
: this.show({
resource: page,
property,
viewer: dash.URIViewer,
})
}

return html`<div>
<span>${link(hydra.first)}</span>
<span>${link(hydra.previous)}</span>
<span>${link(hydra.next)}</span>
<span>${link(hydra.last)}</span>
</div>`
},
}

const tableRowView: Renderer = {
viewer: dash.HydraMemberViewer,
render(member, memberShape) {
return html`
${memberShape?.property.filter(({ hidden }) => !hidden).map(property => html`<td>
${findNodes(member, property.pointer.out(sh.path)).map(resource => html`
${this.show({ resource, shape: memberShape, property })}
`)}
</td>`)}
`
},
}

const galleryView: Renderer = {
viewer: dash.HydraCollectionViewer,
render(collection) {
const memberTypes = collection
.out(hydra.manages)
.has(hydra.property, rdf.type)
.out(hydra.object)

const memberShape = this.shapes.shapes
.find(shape => shape.pointer.has(sh.targetClass, memberTypes).terms.length)

return html`<div>
${collection.out(hydra.member).map(resource => this.show({
resource,
shape: memberShape,
property: hydra.member,
viewer: dash.HydraMemberViewer,
}))}
</div>`
},
}

const galleryMemberView: Renderer = {
viewer: dash.HydraMemberViewer,
render(member) {
const images = member.out(schema.image).toArray()

return html`${images.map(image => html`<div>
${this.show({ resource: image, property: schema.image })}
</div>`)}`
},
}

const imageViewer: ViewerMatchInit = {
viewer: dash.SchemaImageViewer,
match({ resource }) {
return resource.has(rdf.type, schema.ImageObject).terms.length ? 50 : 0
},
}

const imageView: Renderer = {
viewer: dash.SchemaImageViewer,
render(image) {
return html`<div>
<img src="${image.out(schema.contentUrl).value || ''}" alt="${image.out(schema.caption).value || ''}">
</div>`
},
}
import { tableView } from '../viewers/hydra-MembersViewer/table'
import { galleryView } from '../viewers/hydra-MembersViewer/gallery'
import { localizedLabel } from '../viewers/ex-LocalLabelViewer'
import * as pagerViewer from '../viewers/hydra-PartialCollectionViewer'
import * as imageViewer from '../viewers/schema-ImageViewer'

export default {
title: 'Hydra Collection',
}

interface ViewStoryParams {
resource: QuadArrayFactory
viewers: ViewerMatchInit[]
renderers: Array<Renderer | MultiRenderer>
language?: string
viewers: ViewerMatcher[]
renderers: Array<Renderer<any> | MultiRenderer>
}

const Template = template<ViewStoryParams>(({ resource, viewers, renderers, ...params }) => {
const shapes = [
hydraCollectionShape,
schemaPerson,
].map(runFactory).map(p => fromPointer(p))
async function selectShape(arg: MultiPointer) {
if (arg.has(rdf.type, hydra.Collection).terms.length) {
return [runFactory(hydraCollectionShape)]
}
if (arg.has(rdf.type, schema.Person).terms.length) {
return [runFactory(schemaPerson)]
}
if (arg.has(rdf.type, hydra.PartialCollectionView).terms.length) {
return [runFactory(hydraPartialCollectionViewShape)]
}

return []
}

return html`
const Template = template<ViewStoryParams>(({ resource, viewers, renderers }) => html`
<roadshow-view .resource="${runFactory(resource)}"
.shapes="${shapes}"
.shapesLoader="${selectShape}"
.viewers="${viewers}"
.renderers="${renderers}"
.params="${params}"
></roadshow-view>
`
})
`)

export const AddressBookTable = Template.bind({})
AddressBookTable.args = {
resource: addressBook,
viewers: [collectionViewer, pagerViewer, localizedLabelViewer],
renderers: [tableView, tableRowView, pagerView, localizedLabel],
language: '',
viewers: [pagerViewer.matcher],
renderers: [tableView, pagerViewer.renderer, localizedLabel],
}

export const ProfileGallery = Template.bind({})
ProfileGallery.args = {
resource: addressBook,
viewers: [collectionViewer, imageViewer],
renderers: [galleryView, galleryMemberView, imageView],
viewers: [imageViewer.matcher, pagerViewer.matcher],
renderers: [galleryView, imageViewer.renderer, pagerViewer.renderer, localizedLabel],
}
Loading

0 comments on commit 6d73bc9

Please sign in to comment.