diff --git a/.env b/.env index d3646e8..a1d48fe 100644 --- a/.env +++ b/.env @@ -5,6 +5,7 @@ VITE_SIDENAV=true VITE_ENABLED_PREZS=CatPrez,SpacePrez,VocPrez VITE_PER_PAGE=20 VITE_CONCEPT_PER_PAGE=100 +VITE_ENABLE_SCORES=true ## --------------------------------------- ## MAP DISPLAY DEFAULT SETTINGS diff --git a/env.d.ts b/env.d.ts index 24e0ac4..b67725c 100644 --- a/env.d.ts +++ b/env.d.ts @@ -2,6 +2,7 @@ interface ImportMetaEnv { readonly VITE_SIDENAV: string; // true | false readonly VITE_ENABLED_PREZS: string; // CatPrez | SpacePrez | VocPrez comma separated + readonly VITE_ENABLE_SCORES: string; // true | false readonly VITE_PER_PAGE: number; readonly VITE_CONCEPT_PER_PAGE: number; readonly VITE_API_BASE_URL: string; diff --git a/src/components/BaseModal.vue b/src/components/BaseModal.vue index 37526ca..b5dab50 100644 --- a/src/components/BaseModal.vue +++ b/src/components/BaseModal.vue @@ -107,7 +107,7 @@ onUnmounted(() => { $borderColor: #c9c9c9; display: flex; flex-direction: column; - padding: 8px; + padding: 16px; gap: 8px; overflow-y: auto; border-top: 1px solid $borderColor; diff --git a/src/components/CircleProgress.vue b/src/components/CircleProgress.vue new file mode 100644 index 0000000..9c9a8fa --- /dev/null +++ b/src/components/CircleProgress.vue @@ -0,0 +1,93 @@ + + + + + \ No newline at end of file diff --git a/src/components/navs/RightSideBar.vue b/src/components/navs/RightSideBar.vue index 235348b..4b85347 100644 --- a/src/components/navs/RightSideBar.vue +++ b/src/components/navs/RightSideBar.vue @@ -20,11 +20,13 @@ const teleportChildren = computed(() => { @@ -37,6 +39,12 @@ const teleportChildren = computed(() => { display: flex; flex-direction: column; gap: 12px; + + #score-teleport { + display: flex; + flex-direction: column; + gap: 12px; + } } hr { diff --git a/src/components/scores/CareScore.vue b/src/components/scores/CareScore.vue new file mode 100644 index 0000000..c99e7e3 --- /dev/null +++ b/src/components/scores/CareScore.vue @@ -0,0 +1,165 @@ + + + + + \ No newline at end of file diff --git a/src/components/scores/FairScore.vue b/src/components/scores/FairScore.vue new file mode 100644 index 0000000..2690ba2 --- /dev/null +++ b/src/components/scores/FairScore.vue @@ -0,0 +1,166 @@ + + + + + \ No newline at end of file diff --git a/src/components/scores/ScoreWidget.vue b/src/components/scores/ScoreWidget.vue new file mode 100644 index 0000000..2481f7a --- /dev/null +++ b/src/components/scores/ScoreWidget.vue @@ -0,0 +1,18 @@ + + + + + \ No newline at end of file diff --git a/src/config.ts b/src/config.ts index 4c103ef..ec85a40 100644 --- a/src/config.ts +++ b/src/config.ts @@ -3,6 +3,7 @@ export default { enabledPrezs: import.meta.env.VITE_ENABLED_PREZS, perPage: import.meta.env.VITE_PER_PAGE, conceptPerPage: import.meta.env.VITE_CONCEPT_PER_PAGE, + enableScores: import.meta.env.VITE_ENABLE_SCORES, apiBaseUrl: import.meta.env.VITE_API_BASE_URL, map: { settings: { diff --git a/src/main.ts b/src/main.ts index ebb417d..2555333 100644 --- a/src/main.ts +++ b/src/main.ts @@ -3,7 +3,7 @@ import pinia from "@/stores/pinia"; import App from "@/App.vue"; import router from "@/router"; import config from "@/config"; -import { sidenavConfigKey, enabledPrezsConfigKey, apiBaseUrlConfigKey, mapConfigKey, perPageConfigKey, conceptPerPageConfigKey } from "@/types"; +import { sidenavConfigKey, enabledPrezsConfigKey, apiBaseUrlConfigKey, mapConfigKey, perPageConfigKey, conceptPerPageConfigKey, enableScoresKey } from "@/types"; import VueGoogleMaps from '@fawmi/vue-google-maps' @@ -15,6 +15,7 @@ app.provide(sidenavConfigKey, config.sidenav === "true"); app.provide(enabledPrezsConfigKey, config.enabledPrezs.split(",")); app.provide(perPageConfigKey, config.perPage); app.provide(conceptPerPageConfigKey, config.conceptPerPage); +app.provide(enableScoresKey, config.enableScores === "true"); app.provide(apiBaseUrlConfigKey, config.apiBaseUrl.replace(/\/$/, "")); app.provide(mapConfigKey, config.map); diff --git a/src/types.ts b/src/types.ts index 4b9c6a9..0b657c2 100644 --- a/src/types.ts +++ b/src/types.ts @@ -8,6 +8,7 @@ export const sidenavConfigKey: InjectionKey = Symbol(); export const perPageConfigKey: InjectionKey = Symbol(); export const conceptPerPageConfigKey: InjectionKey = Symbol(); export const enabledPrezsConfigKey: InjectionKey = Symbol(); +export const enableScoresKey: InjectionKey = Symbol(); export const apiBaseUrlConfigKey: InjectionKey = Symbol(); export interface MapConfig { diff --git a/src/util/helpers.ts b/src/util/helpers.ts index 7a7b9bd..fd8a137 100644 --- a/src/util/helpers.ts +++ b/src/util/helpers.ts @@ -29,3 +29,7 @@ export function ensureProfiles() { export function copyToClipboard(text: string) { navigator.clipboard.writeText(text.trim()); } + +export function titleCase(s: string): string { + return s.charAt(0).toUpperCase() + s.slice(1).toLowerCase(); +} \ No newline at end of file diff --git a/src/views/ItemListView.vue b/src/views/ItemListView.vue index 0983e9e..6ee1a79 100644 --- a/src/views/ItemListView.vue +++ b/src/views/ItemListView.vue @@ -340,7 +340,7 @@ onMounted(() => { - + diff --git a/src/views/PropTableView.vue b/src/views/PropTableView.vue index aeadc5b..17bef0f 100644 --- a/src/views/PropTableView.vue +++ b/src/views/PropTableView.vue @@ -5,7 +5,7 @@ import { BlankNode, DataFactory, Quad, Store, Literal } from "n3"; import { useUiStore } from "@/stores/ui"; import { useRdfStore } from "@/composables/rdfStore"; import { useGetRequest } from "@/composables/api"; -import { apiBaseUrlConfigKey, conceptPerPageConfigKey, type ListItem, type AnnotatedQuad, type Breadcrumb, type Concept, type PrezFlavour, type Profile, type ListItemExtra, type ListItemSortable } from "@/types"; +import { apiBaseUrlConfigKey, conceptPerPageConfigKey, enableScoresKey, type ListItem, type AnnotatedQuad, type Breadcrumb, type Concept, type PrezFlavour, type Profile, type ListItemExtra, type ListItemSortable } from "@/types"; import PropTable from "@/components/proptable/PropTable.vue"; import ConceptComponent from "@/components/ConceptComponent.vue"; import AdvancedSearch from "@/components/search/AdvancedSearch.vue"; @@ -16,11 +16,13 @@ import MapClient from "@/components/MapClient.vue"; import type { WKTResult } from "@/stores/mapSearchStore.d"; import SortableTabularList from "@/components/SortableTabularList.vue"; import LoadingMessage from "@/components/LoadingMessage.vue"; -import { ensureProfiles } from "@/util/helpers"; +import { ensureProfiles, titleCase } from "@/util/helpers"; +import ScoreWidget from "@/components/scores/ScoreWidget.vue"; const { namedNode } = DataFactory; const apiBaseUrl = inject(apiBaseUrlConfigKey) as string; +const enableScores = inject(enableScoresKey) as boolean; const conceptPerPage = inject(conceptPerPageConfigKey) as number; const route = useRoute(); const ui = useUiStore(); @@ -55,7 +57,8 @@ const hiddenPredicates = ref([ qnameToIri("dcterms:identifier"), qnameToIri("prez:count"), qnameToIri("prez:childrenCount"), - qnameToIri("prez:link") + qnameToIri("prez:link"), + "https://linked.data.gov.au/def/scores/hasScore" ]); const defaultProfile = ref(null); const childrenConfig = ref({ @@ -65,6 +68,8 @@ const childrenConfig = ref({ buttonTitle: "", buttonLink: "" }); +const hasScores = ref(false); +const scores = ref<{[key: string]: {[key: string]: number}}>({}); // {fair: {f: 0, a: 0, i: 0, r: 0}, ...} const hasFewChildren = ref(false); // only for vocab function configByBaseClass(baseClass: string) { @@ -170,6 +175,8 @@ function getProperties() { link: `/object?uri=${item.value.iri}` }) }, q.object, namedNode(qnameToIri("geo:asWKT")), null, null) + } else if (q.predicate.value === "https://linked.data.gov.au/def/scores/hasScore" && enableScores && !hasScores.value) { + hasScores.value = true; } else if (q.predicate.value === qnameToIri("prez:childrenCount")) { item.value.childrenCount = Number(q.object.value); } @@ -183,12 +190,42 @@ function getProperties() { } }, subject, null, null, null); + if (hasScores.value) { + getScores(); + } + // set the item title after the item title has been set geoResults.value.forEach(result => { result.label = item.value.title ? item.value.title : item.value.iri }); } +function getScore(scoreName: string, normalised: boolean = false): {[key: string]: number} { + const scores: {[key: string]: number} = {}; + + store.value.forObjects(o => { + store.value.forEach(q => { + store.value.forObjects(o2 => { + store.value.forEach(q2 => { + const match = q2.predicate.value.match(`https:\/\/linked.data.gov.au\/def\/scores\/${scoreName}([A-Z]){1}Score${normalised ? "Normalised" : ""}`); + if (match) { + scores[match[1].toLowerCase()] = Number(q2.object.value); + } + }, o2, null, null, null); + }, q.subject, namedNode("http://purl.org/linked-data/cube#observation"), null); + }, o, namedNode(qnameToIri("a")), namedNode(`https://linked.data.gov.au/def/scores/${titleCase(scoreName)}Score${normalised ? "Normalised" : ""}`), null); + }, namedNode(item.value.iri), namedNode("https://linked.data.gov.au/def/scores/hasScore"), null); + + return scores; +} + +function getScores() { + scores.value = { + fair: getScore("fair"), + care: getScore("care"), + }; +} + function getBreadcrumbs(): Breadcrumb[] { // if /object, then use home/object/ // else, build out the breadcrumbs using the URL path @@ -677,9 +714,12 @@ onMounted(() => { - + + + +