-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #90 from RDFLib/feature/scoring
FAIR & CARE Scoring Widgets
- Loading branch information
Showing
14 changed files
with
506 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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> |
Oops, something went wrong.