diff --git a/opendata.swiss/ui/content.config.ts b/opendata.swiss/ui/content.config.ts index ceafc25..d4cce49 100644 --- a/opendata.swiss/ui/content.config.ts +++ b/opendata.swiss/ui/content.config.ts @@ -55,6 +55,7 @@ export default defineContentConfig({ label: z.string(), })).optional(), tags: z.array(z.string()).optional(), + rawbody: z.string(), }) }) } diff --git "a/opendata.swiss/ui/content/showcases/mietpreisentwicklung-in-bern-\342\200\223-ein-instrument-f\303\274r-mieter-stadtplaner-und-entscheidungstr\303\244ger.de.md" "b/opendata.swiss/ui/content/showcases/mietpreisentwicklung-in-bern-\342\200\223-ein-instrument-f\303\274r-mieter-stadtplaner-und-entscheidungstr\303\244ger.de.md" index af87afc..6e8b8bc 100644 --- "a/opendata.swiss/ui/content/showcases/mietpreisentwicklung-in-bern-\342\200\223-ein-instrument-f\303\274r-mieter-stadtplaner-und-entscheidungstr\303\244ger.de.md" +++ "b/opendata.swiss/ui/content/showcases/mietpreisentwicklung-in-bern-\342\200\223-ein-instrument-f\303\274r-mieter-stadtplaner-und-entscheidungstr\303\244ger.de.md" @@ -5,8 +5,8 @@ title: Mietpreisentwicklung in Bern – Ein Instrument für Mieter, Stadtplaner image: https://repository-images.githubusercontent.com/788945570/a1998415-fef9-4518-8a5d-d2937f17edec url: https://giodi.github.io/dashboard-wohnungsmietpreise-stadt-bern/ categories: - - SOCI - - REGI + - http://publications.europa.eu/resource/authority/data-theme/SOCI + - http://publications.europa.eu/resource/authority/data-theme/REGI type: application datasets: - id: 85787-bundesamt-fur-statistik-bfs diff --git "a/opendata.swiss/ui/content/showcases/mietpreisentwicklung-in-bern-\342\200\223-ein-instrument-f\303\274r-mieter-stadtplaner-und-entscheidungstr\303\244ger.en.md" "b/opendata.swiss/ui/content/showcases/mietpreisentwicklung-in-bern-\342\200\223-ein-instrument-f\303\274r-mieter-stadtplaner-und-entscheidungstr\303\244ger.en.md" index 003f306..0e39558 100644 --- "a/opendata.swiss/ui/content/showcases/mietpreisentwicklung-in-bern-\342\200\223-ein-instrument-f\303\274r-mieter-stadtplaner-und-entscheidungstr\303\244ger.en.md" +++ "b/opendata.swiss/ui/content/showcases/mietpreisentwicklung-in-bern-\342\200\223-ein-instrument-f\303\274r-mieter-stadtplaner-und-entscheidungstr\303\244ger.en.md" @@ -5,8 +5,8 @@ title: Rent Price Development in Bern – A Tool for Tenants, Urban Planners, an image: https://repository-images.githubusercontent.com/788945570/a1998415-fef9-4518-8a5d-d2937f17edec url: https://giodi.github.io/dashboard-wohnungsmietpreise-stadt-bern/ categories: - - SOCI - - REGI + - http://publications.europa.eu/resource/authority/data-theme/SOCI + - http://publications.europa.eu/resource/authority/data-theme/REGI type: application datasets: - id: 85787-bundesamt-fur-statistik-bfs diff --git "a/opendata.swiss/ui/content/showcases/mietpreisentwicklung-in-bern-\342\200\223-ein-instrument-f\303\274r-mieter-stadtplaner-und-entscheidungstr\303\244ger.fr.md" "b/opendata.swiss/ui/content/showcases/mietpreisentwicklung-in-bern-\342\200\223-ein-instrument-f\303\274r-mieter-stadtplaner-und-entscheidungstr\303\244ger.fr.md" index e1bf763..dabfbc7 100644 --- "a/opendata.swiss/ui/content/showcases/mietpreisentwicklung-in-bern-\342\200\223-ein-instrument-f\303\274r-mieter-stadtplaner-und-entscheidungstr\303\244ger.fr.md" +++ "b/opendata.swiss/ui/content/showcases/mietpreisentwicklung-in-bern-\342\200\223-ein-instrument-f\303\274r-mieter-stadtplaner-und-entscheidungstr\303\244ger.fr.md" @@ -5,8 +5,8 @@ title: Évolution des loyers à Berne – Un outil pour les locataires, urbanist image: https://repository-images.githubusercontent.com/788945570/a1998415-fef9-4518-8a5d-d2937f17edec url: https://giodi.github.io/dashboard-wohnungsmietpreise-stadt-bern/ categories: - - SOCI - - REGI + - http://publications.europa.eu/resource/authority/data-theme/SOCI + - http://publications.europa.eu/resource/authority/data-theme/REGI type: application datasets: - id: 85787-bundesamt-fur-statistik-bfs diff --git "a/opendata.swiss/ui/content/showcases/mietpreisentwicklung-in-bern-\342\200\223-ein-instrument-f\303\274r-mieter-stadtplaner-und-entscheidungstr\303\244ger.it.md" "b/opendata.swiss/ui/content/showcases/mietpreisentwicklung-in-bern-\342\200\223-ein-instrument-f\303\274r-mieter-stadtplaner-und-entscheidungstr\303\244ger.it.md" index 7e39ba6..fe0c4ba 100644 --- "a/opendata.swiss/ui/content/showcases/mietpreisentwicklung-in-bern-\342\200\223-ein-instrument-f\303\274r-mieter-stadtplaner-und-entscheidungstr\303\244ger.it.md" +++ "b/opendata.swiss/ui/content/showcases/mietpreisentwicklung-in-bern-\342\200\223-ein-instrument-f\303\274r-mieter-stadtplaner-und-entscheidungstr\303\244ger.it.md" @@ -5,8 +5,8 @@ title: Andamento degli affitti a Berna – Uno strumento per inquilini, urbanist image: https://repository-images.githubusercontent.com/788945570/a1998415-fef9-4518-8a5d-d2937f17edec url: https://giodi.github.io/dashboard-wohnungsmietpreise-stadt-bern/ categories: - - SOCI - - REGI + - http://publications.europa.eu/resource/authority/data-theme/SOCI + - http://publications.europa.eu/resource/authority/data-theme/REGI type: application datasets: - id: 85787-bundesamt-fur-statistik-bfs diff --git a/opendata.swiss/ui/package-lock.json b/opendata.swiss/ui/package-lock.json index c657b50..64a5330 100644 --- a/opendata.swiss/ui/package-lock.json +++ b/opendata.swiss/ui/package-lock.json @@ -17,6 +17,7 @@ "@pinia/nuxt": "^0.11.1", "@piveau/sdk-core": "^0.0.0-beta.2", "@piveau/sdk-vue": "^1.0.0-beta.10", + "@tpluscode/rdf-ns-builders": "^5.0.0", "better-sqlite3": "^12.2.0", "bootstrap": "^5.3.7", "decap-cms-app": "^3.8.3", @@ -25,9 +26,12 @@ "nuxt": "^4.0.0", "pinia": "^3.0.3", "react-bootstrap-typeahead": "^6.4.1", + "remark": "^15.0.1", + "remark-frontmatter": "^5.0.0", "rimraf": "^6.0.1", "sass-embedded": "^1.89.2", "sharp": "^0.34.3", + "strip-markdown": "^6.0.0", "swiper": "^11.2.10", "uuid": "^11.1.0", "vue": "^3.5.17", @@ -4667,6 +4671,33 @@ "integrity": "sha512-m7bpKCD4QMlFCjA/nKTs23fuvoVFoA83brRKmObCUNmi/9tVu8Ve3w4YQAnJu4q3Tjf5fr685HYIC/IA2zHRSg==", "license": "MIT" }, + "node_modules/@rdfjs/data-model": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@rdfjs/data-model/-/data-model-2.1.1.tgz", + "integrity": "sha512-6mcOI4DjIPS6MOZw23H8oAdujHCk5gippVNQ7mKwliYTvTNh+uqRM91B9OLqhoAoNcQ3t49Dx2ooIMRG9/6ooA==", + "license": "MIT", + "bin": { + "rdfjs-data-model-test": "bin/test.js" + } + }, + "node_modules/@rdfjs/namespace": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@rdfjs/namespace/-/namespace-2.0.1.tgz", + "integrity": "sha512-U85NWVGnL3gWvOZ4eXwUcv3/bom7PAcutSBQqmVWvOaslPy+kDzAJCH1WYBLpdQd4yMmJ+bpJcDl9rcHtXeixg==", + "license": "MIT", + "dependencies": { + "@rdfjs/data-model": "^2.0.1" + } + }, + "node_modules/@rdfjs/types": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@rdfjs/types/-/types-2.0.1.tgz", + "integrity": "sha512-uyAzpugX7KekAXAHq26m3JlUIZJOC0uSBhpnefGV5i15bevDyyejoB7I+9MKeUrzXD8OOUI3+4FeV1wwQr5ihA==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@react-aria/ssr": { "version": "3.9.10", "resolved": "https://registry.npmjs.org/@react-aria/ssr/-/ssr-3.9.10.tgz", @@ -5490,6 +5521,19 @@ } } }, + "node_modules/@tpluscode/rdf-ns-builders": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@tpluscode/rdf-ns-builders/-/rdf-ns-builders-5.0.0.tgz", + "integrity": "sha512-rtMFbArdief+s0z2A3TOb/gNe5O5xn9LDiEpilCf6lGYCUIfyqoOvZY80fS/eILwcF2Mj6cUQN1WBQ+1neJmaw==", + "license": "MIT", + "dependencies": { + "@rdfjs/data-model": "^2.1.0", + "@rdfjs/namespace": "^2.0.1", + "@rdfjs/types": "^2", + "@types/rdfjs__namespace": "^2.0.10", + "@zazuko/prefixes": "^2.3.0" + } + }, "node_modules/@trysound/sax": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", @@ -5606,6 +5650,15 @@ "integrity": "sha512-LriObC2+KYZD3FzCrgWGv/qufdUy4eXrxcLgQMfYXgPbLIecKIsVBaQgUPmxSSLcjmYbDTQbMgr6qr6l/eb7Bg==", "license": "MIT" }, + "node_modules/@types/rdfjs__namespace": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/@types/rdfjs__namespace/-/rdfjs__namespace-2.0.10.tgz", + "integrity": "sha512-xoVzEIOxcpyteEmzaj94MSBbrBFs+vqv05joMhzLEiPRwsBBDnhkdBCaaDxR1Tf7wOW0kB2R1IYe4C3vEBFPgA==", + "license": "MIT", + "dependencies": { + "@rdfjs/types": "*" + } + }, "node_modules/@types/react": { "version": "19.1.12", "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.12.tgz", @@ -6821,6 +6874,12 @@ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", "license": "0BSD" }, + "node_modules/@zazuko/prefixes": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@zazuko/prefixes/-/prefixes-2.4.0.tgz", + "integrity": "sha512-bd53k5XgFKWR56sofHeAcIbv8o0m2HsJlbHaHbrMufUCdgiZsCLvZn84Vh1dhcsyBHOD0EIo9AD4pNWDQLVRaw==", + "license": "MIT" + }, "node_modules/abbrev": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-3.0.1.tgz", @@ -12652,6 +12711,19 @@ "reusify": "^1.0.4" } }, + "node_modules/fault": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fault/-/fault-2.0.1.tgz", + "integrity": "sha512-WtySTkS4OKev5JtpHXnib4Gxiurzh5NCGvWrFaZ34m6JehfTUhKZvn9njTfw48t6JumVQOmrKqpmGcdwxnhqBQ==", + "license": "MIT", + "dependencies": { + "format": "^0.2.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/fdir": { "version": "6.5.0", "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", @@ -12889,6 +12961,14 @@ "node": ">= 6" } }, + "node_modules/format": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/format/-/format-0.2.2.tgz", + "integrity": "sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==", + "engines": { + "node": ">=0.4.x" + } + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -15678,6 +15758,36 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/mdast-util-frontmatter": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-frontmatter/-/mdast-util-frontmatter-2.0.1.tgz", + "integrity": "sha512-LRqI9+wdgC25P0URIJY9vwocIzCcksduHQ9OF2joxQoyTNVduwLAFUzjoopuRJbJAReaKrNQKAZKL3uCMugWJA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "escape-string-regexp": "^5.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "micromark-extension-frontmatter": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-frontmatter/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/mdast-util-gfm": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-3.1.0.tgz", @@ -16214,6 +16324,22 @@ "micromark-util-types": "^2.0.0" } }, + "node_modules/micromark-extension-frontmatter": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-frontmatter/-/micromark-extension-frontmatter-2.0.0.tgz", + "integrity": "sha512-C4AkuM3dA58cgZha7zVnuVxBhDsbttIMiytjgsM2XbHAB2faRVaHRle40558FBN+DJcrLNCoqG5mlrpdU4cRtg==", + "license": "MIT", + "dependencies": { + "fault": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/micromark-extension-gfm": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-3.0.0.tgz", @@ -21728,6 +21854,22 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/remark": { + "version": "15.0.1", + "resolved": "https://registry.npmjs.org/remark/-/remark-15.0.1.tgz", + "integrity": "sha512-Eht5w30ruCXgFmxVUSlNWQ9iiimq07URKeFS3hNc8cUWy1llX4KDWfyEDZRycMc+znsN9Ux5/tJ/BFdgdOwA3A==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "remark-parse": "^11.0.0", + "remark-stringify": "^11.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/remark-emoji": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/remark-emoji/-/remark-emoji-5.0.2.tgz", @@ -21744,6 +21886,22 @@ "node": ">=18" } }, + "node_modules/remark-frontmatter": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/remark-frontmatter/-/remark-frontmatter-5.0.0.tgz", + "integrity": "sha512-XTFYvNASMe5iPN0719nPrdItC9aU0ssC4v14mH1BCi1u0n1gAocqcujWUrByftZTbLhRtiKRyjYTSIOcr69UVQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-frontmatter": "^2.0.0", + "micromark-extension-frontmatter": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/remark-gfm": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.1.tgz", @@ -23843,6 +24001,19 @@ "integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==", "license": "MIT" }, + "node_modules/strip-markdown": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-markdown/-/strip-markdown-6.0.0.tgz", + "integrity": "sha512-mSa8FtUoX3ExJYDkjPUTC14xaBAn4Ik5GPQD45G5E2egAmeV3kHgVSTfIoSDggbF6Pk9stahVgqsLCNExv6jHw==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/structured-clone-es": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/structured-clone-es/-/structured-clone-es-1.0.0.tgz", diff --git a/opendata.swiss/ui/package.json b/opendata.swiss/ui/package.json index 66b3869..65999b4 100644 --- a/opendata.swiss/ui/package.json +++ b/opendata.swiss/ui/package.json @@ -24,6 +24,7 @@ "@pinia/nuxt": "^0.11.1", "@piveau/sdk-core": "^0.0.0-beta.2", "@piveau/sdk-vue": "^1.0.0-beta.10", + "@tpluscode/rdf-ns-builders": "^5.0.0", "better-sqlite3": "^12.2.0", "bootstrap": "^5.3.7", "decap-cms-app": "^3.8.3", @@ -32,9 +33,12 @@ "nuxt": "^4.0.0", "pinia": "^3.0.3", "react-bootstrap-typeahead": "^6.4.1", + "remark": "^15.0.1", + "remark-frontmatter": "^5.0.0", "rimraf": "^6.0.1", "sass-embedded": "^1.89.2", "sharp": "^0.34.3", + "strip-markdown": "^6.0.0", "swiper": "^11.2.10", "uuid": "^11.1.0", "vue": "^3.5.17", diff --git a/opendata.swiss/ui/server/api/showcases.ts b/opendata.swiss/ui/server/api/showcases.ts new file mode 100644 index 0000000..b115dc2 --- /dev/null +++ b/opendata.swiss/ui/server/api/showcases.ts @@ -0,0 +1,91 @@ +import {remark} from 'remark' +import strip from 'strip-markdown' +import remarkFrontmatter from "remark-frontmatter"; +import {dcat, dcterms, rdfs, schema} from "@tpluscode/rdf-ns-builders"; + +const stemPattern = /^showcases\/(?.*)\.(?\w\w)$/ + +interface AggregateShowcase { + id: string + '@type': 'Showcase' + title: Record + image: string | undefined + abstract: Record + categories: string[] + datasets: Array<{ id: string; label: string }> + text: Record + tag: string[] +} + +const ldContext = { + '@base': 'https://example.org/', + id: '@id', + label: rdfs.label.value, + categories: { + '@id': dcat.theme.value, + '@type': '@id' + }, + datasets: { + '@id': dcterms.references.value, + '@type': '@id' + }, + title: { + '@id': dcterms.title.value, + '@container': '@language', + }, + abstract: { + '@id': dcterms.abstract.value, + '@container': '@language', + }, + text: { + '@id': schema.text.value, + '@container': '@language', + }, + image: schema.image.value, + tag: dcat.keyword.value, +}; +export default defineEventHandler(async (event) => { + const showcases = await queryCollection(event, 'showcases') + .select('title', 'categories', 'datasets', 'description', 'rawbody', 'stem', 'image') + .all() + + const aggregatedShowcases = showcases.reduce(async (promise, showcase) => { + const arr = await promise + + const { stem, lang } = showcase.stem.match(stemPattern)?.groups || {} + let aggregate = arr.find(({ id }) => id === stem) + if (!aggregate) { + aggregate = { + id: stem, + '@type': 'Showcase', + title: {}, + image: showcase.image, + abstract: {}, + categories: showcase.categories || [], + datasets: showcase.datasets || [], + text: {}, + tag: [], + } + arr.push(aggregate) + } + + aggregate.title[lang] = showcase.title || undefined + aggregate.abstract[lang] = showcase.description || undefined + aggregate.text[lang] = await stripMarkdown(showcase.rawbody) || undefined + + return arr + }, Promise.resolve([])) + + return { + '@context': ldContext, + '@graph': await aggregatedShowcases + } +}) + +async function stripMarkdown(md: string) { + const stripped = await remark() + .use(strip) + .use(remarkFrontmatter) + .process(md) + return stripped.value.toString() +} diff --git a/opendata.swiss/ui/server/tsconfig.json b/opendata.swiss/ui/server/tsconfig.json new file mode 100644 index 0000000..b9ed69c --- /dev/null +++ b/opendata.swiss/ui/server/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "../.nuxt/tsconfig.server.json" +} diff --git a/opendata.swiss/ui/src/admin/VocabularySelectComponent.jsx b/opendata.swiss/ui/src/admin/VocabularySelectComponent.jsx index 520ec03..efed33f 100644 --- a/opendata.swiss/ui/src/admin/VocabularySelectComponent.jsx +++ b/opendata.swiss/ui/src/admin/VocabularySelectComponent.jsx @@ -41,7 +41,7 @@ export default class VocabularySelectComponent extends PiveauSearchComponent { const res = await fetch(url) const { result: { results }} = await res.json() - return results.map(({pref_label, id}) => ({label: pref_label.de, value: id})) + return results.map(({pref_label, resource}) => ({label: pref_label.de, value: resource})) }) state = {