+
- {{ taxon.rank || 'Combination' }}
+ {{ store.taxon.rank || 'Combination' }}
+ >
+ ✕
+
-
+
diff --git a/src/modules/otus/helpers/schema.js b/src/modules/otus/helpers/schema.js
new file mode 100644
index 0000000..c7b4273
--- /dev/null
+++ b/src/modules/otus/helpers/schema.js
@@ -0,0 +1,87 @@
+const { schema_host } = __APP_ENV__
+
+const TAXON_RANK = {
+ species: [
+ 'http://rs.tdwg.org/ontology/voc/TaxonRank#Species',
+ 'http://www.wikidata.org/entity/Q7432'
+ ],
+ genus: [
+ 'genus',
+ 'http://rs.tdwg.org/ontology/voc/TaxonRank#Genus',
+ 'http://www.wikidata.org/entity/Q34740'
+ ]
+}
+
+function removeEmptyProperties(obj) {
+ const copyObj = { ...obj }
+
+ for (const key in obj) {
+ const value = obj[key]
+
+ if (!value || (Array.isArray(value) && !value.length)) {
+ delete copyObj[key]
+ }
+ }
+
+ return copyObj
+}
+
+function makeUrlPath(path) {
+ return schema_host ? `${schema_host}${path}` : ''
+}
+
+export function defineTaxon({
+ id,
+ childTaxon,
+ parentTaxon,
+ taxonRank,
+ name,
+ scientificName,
+ identifier,
+ commonNames,
+ alternateName
+}) {
+ return removeEmptyProperties({
+ '@type': 'Taxon',
+ '@id': makeUrlPath(id),
+ 'http://purl.org/dc/terms/conformsTo': {
+ '@id': 'https://bioschemas.org/profiles/Taxon/1.0-RELEASE'
+ },
+ additionalType: [
+ 'dwc:Taxon',
+ 'http://rs.tdwg.org/ontology/voc/TaxonConcept#TaxonConcept'
+ ],
+ 'dwc:vernacularName': defineCommonNames(commonNames),
+ name,
+ alternateName: alternateName.map((item) => item.replaceAll(/<\/?i>/g, '')),
+ childTaxon,
+ scientificName: defineTaxonName(scientificName),
+ identifier,
+ taxonRank,
+ parentTaxon: defineTaxonEntity(parentTaxon)
+ })
+}
+
+function defineTaxonName({ name, author, taxonRank }) {
+ return removeEmptyProperties({
+ '@type': 'TaxonName',
+ author,
+ name,
+ taxonRank
+ })
+}
+
+function defineTaxonEntity({ name, taxonRank }) {
+ return {
+ '@type': 'Taxon',
+ name,
+ taxonRank
+ }
+}
+
+function defineCommonNames(commonNames) {
+ return commonNames.map(({ name, language }) => ({
+ '@language': language,
+ '@value': name
+ }))
+}
diff --git a/src/modules/otus/services/TaxonWorks.js b/src/modules/otus/services/TaxonWorks.js
index 601759b..507cdc0 100644
--- a/src/modules/otus/services/TaxonWorks.js
+++ b/src/modules/otus/services/TaxonWorks.js
@@ -37,7 +37,7 @@ export default class TaxonWorks {
})
}
- static getOtuDescendants(otuId, params) {
+ static getTaxonomy(otuId, params) {
return makeAPIRequest.get(`/otus/${otuId}/inventory/taxonomy.json`, {
params
})
diff --git a/src/modules/otus/store/actions/index.js b/src/modules/otus/store/actions/index.js
index 29a98ab..b2fbc8e 100644
--- a/src/modules/otus/store/actions/index.js
+++ b/src/modules/otus/store/actions/index.js
@@ -1,2 +1,3 @@
export * from './loadCatalog'
export * from './loadDistribution'
+export * from './loadTaxonomy'
diff --git a/src/modules/otus/store/actions/loadDistribution.js b/src/modules/otus/store/actions/loadDistribution.js
index 7fedd28..42c4f4f 100644
--- a/src/modules/otus/store/actions/loadDistribution.js
+++ b/src/modules/otus/store/actions/loadDistribution.js
@@ -7,7 +7,7 @@ import TaxonWorks from '../../services/TaxonWorks'
export const actionLoadDistribution = {
async loadDistribution({ otuId, rankString }) {
- const isSpeciesGroup = isRankGrpup('SpeciesGroup', rankString)
+ const isSpeciesGroup = rankString && isRankGrpup('SpeciesGroup', rankString)
const getAggregateShape = async (otuId) => {
TaxonWorks.getOtuDistribution(otuId)
diff --git a/src/modules/otus/store/actions/loadTaxonomy.js b/src/modules/otus/store/actions/loadTaxonomy.js
new file mode 100644
index 0000000..620832b
--- /dev/null
+++ b/src/modules/otus/store/actions/loadTaxonomy.js
@@ -0,0 +1,15 @@
+import TaxonWorks from '../../services/TaxonWorks'
+
+export const actionLoadTaxonomy = {
+ async loadTaxonomy(otuId) {
+ const { data } = await TaxonWorks.getTaxonomy(otuId, {
+ max_descendants_depth: 0,
+ extend: ['common_names']
+ })
+
+ this.taxonomy = {
+ commonNames: data.common_names,
+ synonyms: data.nomenclatural_synonyms
+ }
+ }
+}
diff --git a/src/modules/otus/store/store.js b/src/modules/otus/store/store.js
index b3fdb93..75f6a5d 100644
--- a/src/modules/otus/store/store.js
+++ b/src/modules/otus/store/store.js
@@ -1,6 +1,10 @@
import { defineStore } from 'pinia'
import TaxonWorks from '../services/TaxonWorks'
-import { actionLoadDistribution, actionLoadCatalog } from './actions'
+import {
+ actionLoadDistribution,
+ actionLoadCatalog,
+ actionLoadTaxonomy
+} from './actions'
export const useOtuStore = defineStore('otuStore', {
state: () => {
@@ -17,6 +21,10 @@ export const useOtuStore = defineStore('otuStore', {
sources: [],
stats: {},
timeline: []
+ },
+ taxonomy: {
+ commonNames: [],
+ synonyms: []
}
}
},
@@ -36,6 +44,7 @@ export const useOtuStore = defineStore('otuStore', {
await this.loadOtu(otuId)
await this.loadTaxon(this.otu.taxon_name_id)
await this.loadCatalog(this.otu.taxon_name_id)
+ await this.loadTaxonomy(otuId)
},
async loadImages(otuId) {
@@ -48,6 +57,7 @@ export const useOtuStore = defineStore('otuStore', {
},
...actionLoadDistribution,
- ...actionLoadCatalog
+ ...actionLoadCatalog,
+ ...actionLoadTaxonomy
}
})
diff --git a/src/modules/otus/views/Index.vue b/src/modules/otus/views/Index.vue
index 34cb26f..4aa025e 100644
--- a/src/modules/otus/views/Index.vue
+++ b/src/modules/otus/views/Index.vue
@@ -29,11 +29,7 @@
:lines="2"
class="w-96"
>
-
+
{
+onMounted(async () => {
if (!otu.value || otu.value.id !== Number(route.params.id)) {
- loadInitialData()
+ await loadInitialData()
+ } else {
+ updateMetadata()
}
})
async function loadInitialData() {
store.$reset()
await store.loadInit(route.params.id)
+ updateMetadata()
+}
+
+function updateMetadata() {
+ useSchemaOrg([
+ defineTaxon({
+ id: route.fullPath,
+ name: taxon.value.full_name,
+ scientificName: {
+ name: taxon.value.full_name,
+ author: taxon.value.author,
+ taxonRank: taxon.value.rank
+ },
+ parentTaxon: {
+ name: taxon.value.parent.full_name,
+ taxonRank: taxon.value.parent.rank
+ },
+ commonNames: store.taxonomy.commonNames,
+ alternateName: store.taxonomy.synonyms
+ })
+ ])
useHead({
title: `${__APP_ENV__.project_name} - ${taxon.value.full_name}`
diff --git a/src/ssr/utils/registerFakeClientComponents.js b/src/ssr/utils/registerFakeClientComponents.js
new file mode 100644
index 0000000..91cce62
--- /dev/null
+++ b/src/ssr/utils/registerFakeClientComponents.js
@@ -0,0 +1,18 @@
+import { defineComponent } from 'vue'
+import glob from 'glob'
+
+export function registerFakeClientComponents(app) {
+ const filePaths = glob.sync('src/components/**/*.client.vue')
+ const vueComponent = defineComponent({
+ template: ''
+ })
+
+ filePaths.forEach((path) => {
+ const componentName = path
+ .split('/')
+ .pop()
+ .replace(/\.client.\w+$/, '')
+
+ app.component(componentName, vueComponent)
+ })
+}