forked from geolba/tethys.frontend
- added DataMetricsBadge.vue component for showing metrics downloads, views and citations
- npm updates - new major version typescript 5
This commit is contained in:
parent
f1fbc2d917
commit
cfc81f2d90
17 changed files with 1191 additions and 612 deletions
136
src/components/datacite/BaseWidget.ts
Normal file
136
src/components/datacite/BaseWidget.ts
Normal file
|
@ -0,0 +1,136 @@
|
|||
import axios from "axios";
|
||||
import { ComponentBase, Vue, Prop } from "vue-facing-decorator";
|
||||
import testLogo from "@/assets/datacite/testLogo.vue";
|
||||
|
||||
const APIURL = "https://api.datacite.org";
|
||||
|
||||
@ComponentBase({
|
||||
name: "BaseWidget",
|
||||
components: {
|
||||
testLogo,
|
||||
},
|
||||
})
|
||||
export default class BaseWidget extends Vue {
|
||||
@Prop({
|
||||
type: Object,
|
||||
required: false,
|
||||
validator(value) {
|
||||
const keys = Object.keys(value);
|
||||
return ["citations", "views", "downloads"].some((r) => keys.includes(r));
|
||||
},
|
||||
})
|
||||
dataInput = {};
|
||||
|
||||
@Prop({
|
||||
type: String,
|
||||
required: true,
|
||||
validator(value) {
|
||||
return value.match(/^10\.\d{4,5}\/[-._;()/:a-zA-Z0-9*~$=]+/);
|
||||
},
|
||||
})
|
||||
doi!: string;
|
||||
|
||||
@Prop({
|
||||
type: String,
|
||||
required: true,
|
||||
validator(value) {
|
||||
return ["small", "medium", "datacite", "regular"].indexOf(value) > -1;
|
||||
},
|
||||
})
|
||||
display!: string;
|
||||
|
||||
public views = "";
|
||||
public citations = "";
|
||||
public downloads = "";
|
||||
private datacite: string | number = "";
|
||||
private loading = false;
|
||||
private errored = false;
|
||||
|
||||
get url() {
|
||||
return `${APIURL}/graphql`;
|
||||
}
|
||||
|
||||
get link() {
|
||||
return `https://commons.datacite.org/doi.org/${this.doi}`;
|
||||
}
|
||||
// get dataInputApi() {
|
||||
// return this.viewsDistribution;
|
||||
// }
|
||||
get alt() {
|
||||
return `${Number(this.views)} Views ${Number(this.downloads)} Downloads ${Number(this.citations)} Citations from DataCite`;
|
||||
}
|
||||
get tooltip() {
|
||||
let message = "";
|
||||
message += `${this.doi} `;
|
||||
message += this.datacite ? `${this.datacite} from DataCite ` : "";
|
||||
return message;
|
||||
}
|
||||
|
||||
getMetrics() {
|
||||
if (this.isLocal() === false) {
|
||||
this.requestMetrics();
|
||||
} else {
|
||||
this.grabMetrics(this.dataInput);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public pluralize(value: number | string = 0, label: string) {
|
||||
if (value === 1) {
|
||||
return `${value.toLocaleString("en-us")} ${label}`;
|
||||
}
|
||||
return `${value.toLocaleString("en-us")} ${label}s`;
|
||||
}
|
||||
|
||||
public formatNumbers(num: any) {
|
||||
if (num < 1e3) return num;
|
||||
if (num >= 1e3 && num < 1e6) return `${+(num / 1e3).toFixed(1)}K`;
|
||||
if (num >= 1e6 && num < 1e9) return `${+(num / 1e6).toFixed(1)}M`;
|
||||
if (num >= 1e9 && num < 1e12) return `${+(num / 1e9).toFixed(1)}B`;
|
||||
if (num >= 1e12) return `${+(num / 1e12).toFixed(1)}T`;
|
||||
return num;
|
||||
}
|
||||
|
||||
private isLocal(): boolean {
|
||||
if (this.dataInput == null && typeof this.doi !== "undefined") {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private grabMetrics(data: any) {
|
||||
this.views = (this.formatNumbers(data.views) as string) || "";
|
||||
this.downloads = (this.formatNumbers(data.downloads) as string) || "";
|
||||
this.citations = (this.formatNumbers(data.citations) as string) || "";
|
||||
this.datacite = this.formatNumbers(data.datacite) || "";
|
||||
}
|
||||
|
||||
private requestMetrics() {
|
||||
axios({
|
||||
url: this.url,
|
||||
method: "post",
|
||||
data: {
|
||||
query: `
|
||||
{
|
||||
counts: work(id: "${this.doi}") {
|
||||
id
|
||||
views: viewCount
|
||||
downloads: downloadCount
|
||||
citations: citationCount
|
||||
}
|
||||
}
|
||||
`,
|
||||
},
|
||||
})
|
||||
.then((response) => {
|
||||
this.grabMetrics(response.data.data.counts);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error);
|
||||
this.errored = true;
|
||||
})
|
||||
.finally(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
}
|
||||
}
|
43
src/components/datacite/BaseWidget.vue
Normal file
43
src/components/datacite/BaseWidget.vue
Normal file
|
@ -0,0 +1,43 @@
|
|||
<script lang="ts">
|
||||
import BaseWidget from "./BaseWidget";
|
||||
export default BaseWidget;
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style scoped>
|
||||
/* https://stackoverflow.com/questions/12675622/script1028-expected-identifier-string-or-number */
|
||||
.icon-metrics {
|
||||
width: 17px;
|
||||
height: 17px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
a {
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
font-family: "Cairo", "Helvetica", Arial, sans-serif;
|
||||
vertical-align: top;
|
||||
}
|
||||
a {
|
||||
color: #222222;
|
||||
-webkit-transition: all 150ms linear;
|
||||
-moz-transition: all 150ms linear;
|
||||
-o-transition: all 150ms linear;
|
||||
-ms-transition: all 150ms linear;
|
||||
transition: all 150ms linear;
|
||||
text-decoration: none;
|
||||
}
|
||||
a:hover,
|
||||
a:focus {
|
||||
color: #222222;
|
||||
text-decoration: none;
|
||||
}
|
||||
a:focus,
|
||||
a:active {
|
||||
outline: 0;
|
||||
}
|
||||
a,
|
||||
a:visited {
|
||||
text-decoration: none;
|
||||
}
|
||||
</style>
|
63
src/components/datacite/DataMetricsBadge.vue
Normal file
63
src/components/datacite/DataMetricsBadge.vue
Normal file
|
@ -0,0 +1,63 @@
|
|||
<template>
|
||||
<div v-bind:title="'Metrics for DOI: ' + doi">
|
||||
<div v-if="doi">
|
||||
<!-- <div v-if="display == 'small'"> -->
|
||||
<SmallWidget v-bind:doi="doi" v-bind:display="display" :data-input="dataObject" />
|
||||
<!-- </div> -->
|
||||
</div>
|
||||
<a v-else>There is no DOI</a>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import SmallWidget from "./SmallWidget.vue";
|
||||
// import MediumWidget from "./MediumWidget.vue";
|
||||
// import DataCiteWidget from "./DataCiteWidget.vue";
|
||||
// import RegularWidget from "./RegularWidget.vue";
|
||||
|
||||
import { Vue, Component, Prop } from "vue-facing-decorator";
|
||||
|
||||
@Component({
|
||||
name: "DataMetricsBadge",
|
||||
components: {
|
||||
// MediumWidget,
|
||||
SmallWidget,
|
||||
// DataCiteWidget,
|
||||
// RegularWidget,
|
||||
},
|
||||
})
|
||||
export default class DataMetricsBadge extends Vue {
|
||||
name = "DataMetricsBadge";
|
||||
funtional = true;
|
||||
|
||||
@Prop({
|
||||
type: Object,
|
||||
})
|
||||
dataInput!: object;
|
||||
|
||||
@Prop({
|
||||
type: String,
|
||||
default: "",
|
||||
})
|
||||
doi!: string;
|
||||
|
||||
@Prop({
|
||||
type: String,
|
||||
required: false,
|
||||
validator(value) {
|
||||
return ["small", "medium", "datacite", "regular"].indexOf(value) > -1;
|
||||
},
|
||||
default: "small",
|
||||
})
|
||||
display!: string;
|
||||
|
||||
get dataObject() {
|
||||
// if (typeof this.dataInput !== "undefined") {
|
||||
return this.dataInput;
|
||||
// }
|
||||
// return null;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
143
src/components/datacite/SmallWidget.vue
Normal file
143
src/components/datacite/SmallWidget.vue
Normal file
|
@ -0,0 +1,143 @@
|
|||
<template>
|
||||
<div class="small-container">
|
||||
<a v-bind:href="link">
|
||||
<div class="d-flex">
|
||||
<!-- <test-logo v-bind:class="'svglogo'" /> -->
|
||||
<div v-bind:class="['', '0', 0].includes(citations) == false ? activeClass : inactiveClass">Citations</div>
|
||||
<div class="p-2 counts" v-bind:title="pluralize(citations, 'Citation')">
|
||||
{{ formatNumbers(["", "0", 0].includes(citations) == false ? citations : " ") }}
|
||||
</div>
|
||||
<div class="p-2 span" />
|
||||
|
||||
<div v-if="parseInt(views) + parseInt(downloads) > 0" class="d-flex">
|
||||
<div v-bind:class="['', '0', 0].includes(views) == false ? activeClass : inactiveClass">Views</div>
|
||||
<div class="p-2 counts" v-bind:title="pluralize(views, 'View')">
|
||||
{{ formatNumbers(["", "0", 0].includes(views) == false ? views : " ") }}
|
||||
</div>
|
||||
<div class="p-2 span" />
|
||||
|
||||
<div v-bind:class="['', '0', 0].includes(downloads) == false ? activeClass : inactiveClass">Downloads</div>
|
||||
<div class="p-2 counts" v-bind:title="pluralize(downloads, 'Download')">
|
||||
{{ formatNumbers(["", "0", 0].includes(downloads) == false ? downloads : " ") }}
|
||||
</div>
|
||||
<div class="p-2 span" />
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component } from "vue-facing-decorator";
|
||||
import BaseWidget from "./BaseWidget.vue";
|
||||
// import testLogo from "@/assets/datacite/testLogo.vue";
|
||||
|
||||
@Component({
|
||||
name: "SmallWidget",
|
||||
})
|
||||
export default class SmallWidget extends BaseWidget {
|
||||
public activeClass = "p-2 label";
|
||||
public inactiveClass = "p-2 label-empty";
|
||||
|
||||
public mounted(): void {
|
||||
this.getMetrics();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
div.label {
|
||||
background-color: rgba(0, 89, 173);
|
||||
display: table;
|
||||
width: 8%;
|
||||
color: white;
|
||||
font-size: 12px;
|
||||
border-style: solid;
|
||||
/* font-weight: bold; */
|
||||
border-color: rgba(0, 89, 173);
|
||||
border-width: thin;
|
||||
/* text-align: center; */
|
||||
height: 15px;
|
||||
}
|
||||
|
||||
div.logo {
|
||||
min-width: 100px;
|
||||
padding: 0px 0px 0px 0px;
|
||||
height: 15px;
|
||||
}
|
||||
|
||||
.svglogo {
|
||||
color: #455a64;
|
||||
fill: #455a64;
|
||||
display: table;
|
||||
width: 20%;
|
||||
min-width: 100px;
|
||||
}
|
||||
|
||||
div.counts {
|
||||
background-color: white;
|
||||
display: table;
|
||||
/* font-size: 2.5vh; */
|
||||
font-size: 12px;
|
||||
width: 6%;
|
||||
border-style: solid;
|
||||
font-weight: bold;
|
||||
border-color: #78909c;
|
||||
border-width: thin;
|
||||
text-align: center;
|
||||
height: 15px;
|
||||
}
|
||||
|
||||
div.span {
|
||||
background-color: white;
|
||||
display: table;
|
||||
font-size: 2.5vh;
|
||||
width: 2%;
|
||||
}
|
||||
|
||||
.small-container {
|
||||
width: 100%;
|
||||
min-width: 400px;
|
||||
max-width: 400px;
|
||||
/*
|
||||
max-height: 15px;
|
||||
padding-right: 15px;
|
||||
padding-left: 15px; */
|
||||
margin-right: auto;
|
||||
margin-left: auto;
|
||||
/* font-family: Arial, Helvetica, sans-serif; */
|
||||
}
|
||||
|
||||
.d-flex {
|
||||
display: -ms-flexbox !important;
|
||||
display: flex !important;
|
||||
}
|
||||
|
||||
.p-2 {
|
||||
padding: 0.1rem !important;
|
||||
}
|
||||
|
||||
.label-empty {
|
||||
background-color: #78909c;
|
||||
display: table;
|
||||
width: 8%;
|
||||
color: white;
|
||||
/* font-size: 2.5vh; */
|
||||
font-size: 12px;
|
||||
border-style: solid;
|
||||
font-weight: bold;
|
||||
border-color: #78909c;
|
||||
border-width: thin;
|
||||
text-align: center;
|
||||
height: 15px;
|
||||
}
|
||||
|
||||
.row {
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-ms-flex-wrap: wrap;
|
||||
flex-wrap: wrap;
|
||||
margin-right: -15px;
|
||||
margin-left: -15px;
|
||||
}
|
||||
</style>
|
Loading…
Add table
editor.link_modal.header
Reference in a new issue