Skip to content

Commit

Permalink
Merge pull request #90 from RDFLib/feature/scoring
Browse files Browse the repository at this point in the history
FAIR & CARE Scoring Widgets
  • Loading branch information
jamiefeiss authored Aug 8, 2023
2 parents af4e806 + 685288c commit 908006d
Show file tree
Hide file tree
Showing 14 changed files with 506 additions and 7 deletions.
1 change: 1 addition & 0 deletions .env
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions env.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion src/components/BaseModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
93 changes: 93 additions & 0 deletions src/components/CircleProgress.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
<script lang="ts" setup>
import { computed } from "vue";
// import ToolTip from "@/components/ToolTip.vue";
const props = defineProps<{
value?: number;
max?: number;
percentage?: number;
label?: string;
tickWhenComplete?: boolean;
gradient?: boolean;
// tooltip?: boolean;
}>();
const percent = computed(() => {
if (props.value !== undefined && props.max !== undefined) {
return props.value / props.max * 100;
} else if (props.percentage !== undefined) {
return props.percentage;
} else {
return 0;
}
});
const percentColour = computed(() => {
if (percent.value < 34) {
return "230, 0, 0"; // red
} else if (percent.value <= 80) {
return "255, 165, 0"; // orange
} else if (percent.value < 100) {
return "175, 230, 0"; // light yellowish-green
} else if (percent.value == 100) {
return "0, 230, 38"; // green
} else {
return "128, 128, 128"; // grey, invalid
}
});
const percentColourHsl = computed(() => {
const startColour = 0; // red
const endColour = 75; // light yellowish-green
const completeColour = 130; // green
const hue = percent.value === 100 ? completeColour : (endColour - startColour) * percent.value / 100;
return `${hue}, 100%, 45%`;
// 0, 0%, 50% // invalid
});
</script>

<template>
<!-- <component :is="props.tooltip ? ToolTip : 'slot'"> -->
<div :class="`circle-progress`" :style="{ background: `conic-gradient(${props.gradient ? `hsl(${percentColourHsl}` : `rgb(${percentColour}`}) ${percent}%, 0, ${props.gradient ? `hsla(${percentColourHsl}` : `rgba(${percentColour}`}, 0.2) ${100 - percent}%)` }">
<div class="circle-overlay">
<span class="circle-value">
<template v-if="props.label">{{ props.label }}</template>
<template v-else-if="props.tickWhenComplete && percent === 100"><i class="fa-solid fa-check"></i></template>
<template v-else-if="props.value !== undefined && props.max !== undefined">{{ props.value }}/{{ props.max }}</template>
<template v-else-if="props.percentage !== undefined">{{ props.percentage }}%</template>
</span>
</div>
</div>
<!-- <template v-if="props.tooltip" #text>
<template v-if="props.value !== undefined && props.max !== undefined">{{ props.value }}/{{ props.max }}</template>
<template v-else-if="props.percentage !== undefined">{{ props.percentage }}%</template>
</template>
</component> -->
</template>

<style lang="scss" scoped>
.circle-progress {
border-radius: 50%;
height: 100%;
width: 100%;
aspect-ratio: 1;
position: relative;
.circle-overlay {
border-radius: 50%;
background-color: white;
display: flex;
align-items: center;
justify-content: center;
position: absolute;
inset: 0.5rem;
.circle-value {
font-size: 0.9em;
}
}
}
</style>
8 changes: 8 additions & 0 deletions src/components/navs/RightSideBar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,13 @@ const teleportChildren = computed(() => {

<template>
<div id="right-nav">
<div id="search-teleport"></div>
<div id="right-bar-content" ref="teleportRef"></div>
<hr v-if="(props.profiles && props.profiles.length > 0) && teleportChildren > 0"/>
<Transition name="fade">
<AltNav v-show="!!props.profiles && props.profiles.length > 0" :profiles="props.profiles" :currentUrl="props.currentUrl" />
</Transition>
<div id="score-teleport"></div>
</div>
</template>

Expand All @@ -37,6 +39,12 @@ const teleportChildren = computed(() => {
display: flex;
flex-direction: column;
gap: 12px;
#score-teleport {
display: flex;
flex-direction: column;
gap: 12px;
}
}
hr {
Expand Down
165 changes: 165 additions & 0 deletions src/components/scores/CareScore.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
<script lang="ts" setup>
import { ref } from "vue";
import CircleProgress from "@/components/CircleProgress.vue";
import BaseModal from "@/components/BaseModal.vue";
// need max scores per sub-score
const MAX_SCORES: {[key: string]: number} = {
c: 8,
a: 9,
r: 9,
e: 3
};
// need details for each sub-score
const props = defineProps<{
score: {[key: string]: number};
}>();
const showModal = ref<boolean>(false);
</script>

<template>
<div class="care-scores">
<div class="score-title">
<h5>CARE Score</h5>
<button class="btn outline" @click="showModal = true" title="Show details"><i class="fa-regular fa-circle-info"></i></button>
</div>
<div class="circles">
<div v-for="score in 'care'" class="circle">
<CircleProgress :value="props.score[score]" :max="MAX_SCORES[score]" tickWhenComplete />
<div class="circle-name">{{ score.toUpperCase() }}</div>
</div>
</div>
</div>
<BaseModal v-if="showModal" @modalClosed="showModal = false">
<template #headerMiddle><h3>CARE Scores</h3></template>
<p>The CARE principles, developed by the <a href="https://www.gida-global.org/care" target="_blank" rel="noopener noreferrer">Global Indigenous Data Alliance (GIDA)</a>, reflect the crucial role of data in advancing Indigenous innovation and self-determination. They ensure that data movements like the open data movement, whatever they're advocating and pursuing, respect the people and purpose behind the data.</p>
<div class="score-details">
<div class="score-detail">
<div class="score-detail-title">
<CircleProgress :value="props.score.c" :max="MAX_SCORES.c" />
<h4>C - Collective Benefit</h4>
</div>
<div class="score-detail-desc">
<p>Data ecosystems shall be designed and function in ways that enable Indigenous Peoples to derive benefit from the data.</p>
</div>
</div>
<div class="score-detail">
<div class="score-detail-title">
<CircleProgress :value="props.score.a" :max="MAX_SCORES.a" />
<h4>A - Authority to Control</h4>
</div>
<div class="score-detail-desc">
<p>Indigenous Peoples' rights and interests in Indigenous data must be recognised and their authority to control such data be empowered.</p>
</div>
</div>
<div class="score-detail">
<div class="score-detail-title">
<CircleProgress :value="props.score.r" :max="MAX_SCORES.r" />
<h4>R - Responsibility</h4>
</div>
<div class="score-detail-desc">
<p>Those working with Indigenous data have a responsibility to share how those data are used to support Indigenous Peoples' self-determination and collective benefit.</p>
</div>
</div>
<div class="score-detail">
<div class="score-detail-title">
<CircleProgress :value="props.score.e" :max="MAX_SCORES.e" />
<h4>E - Ethics</h4>
</div>
<div class="score-detail-desc">
<p>Indigenous Peoples' rights and wellbeing should be the primary concern at all stages of the data life cycle and across the data ecosystem.</p>
</div>
</div>
</div>
</BaseModal>
</template>

<style lang="scss" scoped>
.care-scores {
display: flex;
flex-direction: column;
gap: 12px;
.score-title {
display: flex;
flex-direction: row;
gap: 8px;
align-items: center;
justify-content: space-between;
h5 {
margin: 0;
font-size: 1rem;
}
}
.circles {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 8px;
.circle {
display: flex;
flex-direction: column;
gap: 6px;
align-items: center;
.circle-name {
}
}
}
}
.score-details {
display: flex;
flex-direction: column;
gap: 12px;
.score-detail {
background-color: var(--cardBg);
border-radius: 4px;
overflow: hidden;
$padding: 8px;
.score-detail-title {
display: flex;
flex-direction: row;
gap: 8px;
align-items: center;
// justify-content: space-between;
margin-bottom: 8px;
border-bottom: 1px solid #9d9d9d;
padding: $padding;
.circle-progress {
$size: 56px;
height: $size;
width: $size;
:deep(.circle-overlay) {
// background-color: $titleBg;
background-color: var(--cardBg);
.circle-value {
font-size: 0.85em;
}
}
}
}
.score-detail-desc {
padding: $padding;
}
}
}
p {
margin-top: 0;
margin-bottom: 6px;
}
</style>
Loading

0 comments on commit 908006d

Please sign in to comment.