From 1f4fe3327245eb1d6d5f7d32c7c0027853fa7d5f Mon Sep 17 00:00:00 2001 From: Remi PLANEL <rplanel@pasteur.fr> Date: Thu, 7 Sep 2023 19:07:54 +0200 Subject: [PATCH] composable to fetch doi + expandable card to display abstract --- components/content/ArticleDoi.vue | 43 +++++++++ components/content/ArticleDoiList.vue | 11 +++ components/content/ReferencesList.vue | 63 +++++++------ composables/useFetchArticle.ts | 92 +++++++++++++++++++ .../1.abortive-infection.md | 4 + content/2.defense-systems/abia.md | 2 +- content/2.defense-systems/avast.md | 12 +-- content/2.defense-systems/paris.md | 4 +- pages/[...slug].vue | 4 +- 9 files changed, 194 insertions(+), 41 deletions(-) create mode 100644 components/content/ArticleDoi.vue create mode 100644 components/content/ArticleDoiList.vue create mode 100644 composables/useFetchArticle.ts diff --git a/components/content/ArticleDoi.vue b/components/content/ArticleDoi.vue new file mode 100644 index 00000000..03ce4602 --- /dev/null +++ b/components/content/ArticleDoi.vue @@ -0,0 +1,43 @@ +<script setup lang="ts"> +const props = defineProps<{ + doi: string; +}>(); + +const { article } = useFetchArticle(props.doi) + +const show = ref(false) +console.log(article) + +</script> +<template> + <v-list-item :href="article?.href" :target="article?.target"> + <template #prepend> + <v-avatar> + <v-icon>{{ article?.prependIcon }}</v-icon> + </v-avatar> + </template> + <v-card flat color="transparent" density="compact"> + + <v-card-item density="compact"> + <v-card-title><span class="text-subtitle-1 font-weight-bold">{{ article?.title ?? 'no title' }}</span></v-card-title> + <v-card-subtitle> {{ article?.subtitle ?? "no subtitle" }}</v-card-subtitle> + <v-card-subtitle> {{ article?.containerTitle ?? "no containerTitle" }} ({{ article?.year + }})</v-card-subtitle> + </v-card-item> + <v-card-actions v-if="article?.abstract" density="compact"> + <v-btn size="x-small" variant="outlined" :append-icon="show ? 'mdi-chevron-up' : 'mdi-chevron-down'" + @click.stop.prevent="show = !show">Abstract</v-btn> + </v-card-actions> + + <v-expand-transition> + <v-card v-show="show" flat color="transparent"> + <v-card-text> + {{ article?.abstract }} + </v-card-text> + </v-card> + + </v-expand-transition> + </v-card> + </v-list-item> + <v-divider inset></v-divider> +</template> \ No newline at end of file diff --git a/components/content/ArticleDoiList.vue b/components/content/ArticleDoiList.vue new file mode 100644 index 00000000..c436e9ab --- /dev/null +++ b/components/content/ArticleDoiList.vue @@ -0,0 +1,11 @@ +<script setup lang="ts"> +const props = defineProps<{ + items: string[]; +}>(); +</script> +<template> + <v-list> + <ArticleDoi v-for="item in items" :key="item" :doi="item" /> + + </v-list> +</template> \ No newline at end of file diff --git a/components/content/ReferencesList.vue b/components/content/ReferencesList.vue index 4f9b0868..c6172307 100644 --- a/components/content/ReferencesList.vue +++ b/components/content/ReferencesList.vue @@ -1,30 +1,3 @@ -<template> - <ClientOnly fallback-tag="span" fallback="Loading references..."> - <v-list v-if="computedItems.length > 0"> - <v-list-item v-for="item in computedItems" :key="item.title" :title="item.title" lines="three" :href="item.href" - :target="item.target"> - <template #title="{ title }"> - <span class="font-weight-bold">{{ title }}</span> - </template> - <template #prepend> - <v-avatar> - <v-icon>{{ item.prependIcon }}</v-icon> - </v-avatar> - </template> - <template #subtitle> - <div>{{ item.subtitle }}</div> - <div>{{ item.containerTitle }} ({{ item.year }})</div> - </template> - <v-card flat color="transparent" class="text-justify my-2"> - {{ item.abstract }} - </v-card> - </v-list-item> - - - </v-list> - </ClientOnly> -</template> - <script setup lang="ts"> import { computed, ref } from "vue"; import { useFetch as useFetchVueUse } from "@vueuse/core"; @@ -35,6 +8,10 @@ const props = defineProps<{ items: string[]; }>(); + + +const panel = ref([0, 1]) +const disabled = ref(false) const doiBaseUrl = ref(new URL("https://doi.org/")); const fetchedDoi = ref( await Promise.all( @@ -107,3 +84,35 @@ function getReferenceUrl(doi) { return new URL(doi, doiBaseUrl.value).href; } </script> + + +<template> + <ClientOnly fallback-tag="span" fallback="Loading references..."> + + + <v-list v-if="computedItems.length > 0"> + <v-list-item v-for="item in computedItems" :key="item.title" :title="item.title" lines="three" :href="item.href" + :target="item.target"> + <template #title="{ title }"> + <span class="font-weight-bold">{{ title }}</span> + </template> + <template #prepend> + <v-avatar> + <v-icon>{{ item.prependIcon }}</v-icon> + </v-avatar> + </template> + <template #subtitle> + <div>{{ item.subtitle }}</div> + <div>{{ item.containerTitle }} ({{ item.year }})</div> + </template> + <v-card flat color="transparent" class="text-justify my-2"> + {{ item.abstract }} + </v-card> + </v-list-item> + + + </v-list> + </ClientOnly> +</template> + + diff --git a/composables/useFetchArticle.ts b/composables/useFetchArticle.ts new file mode 100644 index 00000000..918e837f --- /dev/null +++ b/composables/useFetchArticle.ts @@ -0,0 +1,92 @@ +export interface ArticleMessage { + DOI: string; + issue: number; + title: string; + author: Array<{ family: string; given: string }>; + "container-title-short": string; + "container-title": string; + abstract: string; + published: { + "date-parts": string[]; + }; +} + + +export interface Article { + DOI: string + title: string + subtitle: string + containerTitle: string + abstract: string + year: string + href: string + target: string + prependIcon: string +} +export interface RawArticle { + message: ArticleMessage + +} + + + +export function useFetchArticle(doi: string) { + + const article = ref<Article | null>(null) + const pending = ref(false) + const doiBaseUrl = ref(new URL("https://doi.org/")); + const url = ref(new URL(`/works/${doi}`, " https://api.crossref.org/").href); + console.log("dans useFetchArticle") + console.log(url.value) + watchEffect(async () => { + console.log("dans watch effect") + article.value = null + const { data, pending: pendingUseFetch, error, refresh } = await useFetch<RawArticle>(toValue(url), { + }) + console.log(data) + if (data.value?.message) { + const { + DOI, + title, + "container-title-short": cts, + "container-title": ct, + abstract, + published, + author, + ...rest + } = data.value.message; + let sanitizedAbstract = abstract + console.log(DOI) + if (sanitizedAbstract) { + sanitizedAbstract = /\<jats\:p\>(.*)\<\/jats\:p\>/.exec(sanitizedAbstract)?.[1] ?? '' + } + article.value = { + DOI, + title: title[0], + subtitle: toAuthorsString(author || []), + containerTitle: cts?.length > 0 ? cts[0] : ct?.length > 0 ? ct[0] : "", + abstract: sanitizedAbstract, + year: published["date-parts"][0][0], + href: getReferenceUrl(DOI), + target: "_blank", + prependIcon: "mdi-newspaper-variant-outline", + } + console.log(article.value) + } + pending.value = pendingUseFetch.value + + + }) + function toAuthorsString(authors: Array<{ family: string; given: string }>) { + return authors + .map((curr) => { + return `${curr.family} ${curr.given}`; + }) + .join(", "); + } + + function getReferenceUrl(doi: string) { + return new URL(doi, doiBaseUrl.value).href; + } + return { article, pending } +} \ No newline at end of file diff --git a/content/1.general-concepts/1.abortive-infection.md b/content/1.general-concepts/1.abortive-infection.md index 11d861e5..2e5c1975 100644 --- a/content/1.general-concepts/1.abortive-infection.md +++ b/content/1.general-concepts/1.abortive-infection.md @@ -6,3 +6,7 @@ toc: true This section is empty. You can help by adding to it. + + +## test article + diff --git a/content/2.defense-systems/abia.md b/content/2.defense-systems/abia.md index b10dd9da..ea5fc81f 100644 --- a/content/2.defense-systems/abia.md +++ b/content/2.defense-systems/abia.md @@ -33,7 +33,7 @@ A system from *lactococcal plasmid* in *lactococci* has an anti-phage effect aga ## Relevant abstracts -::references-list +::article-doi-list --- items: - 10.1016/j.mib.2005.06.006 diff --git a/content/2.defense-systems/avast.md b/content/2.defense-systems/avast.md index e3f5aca2..7909a710 100644 --- a/content/2.defense-systems/avast.md +++ b/content/2.defense-systems/avast.md @@ -94,18 +94,10 @@ Subsystem CcAvs4 with a system from *Corallococcus coralloides* in *Escherichia ## Relevant abstracts - -::references-list +::article-doi-list --- items: - 10.1126/science.abm4096 - 10.1126/science.aba0372 --- -:: - -**Gao, L. A. et al. Prokaryotic innate immunity through pattern recognition of conserved viral proteins. Science 377, eabm4096 (2022).** -Many organisms have evolved specialized immune pattern-recognition receptors, including nucleotide-binding oligomerization domain-like receptors (NLRs) of the STAND superfamily that are ubiquitous in plants, animals, and fungi. Although the roles of NLRs in eukaryotic immunity are well established, it is unknown whether prokaryotes use similar defense mechanisms. Here, we show that antiviral STAND (Avs) homologs in bacteria and archaea detect hallmark viral proteins, triggering Avs tetramerization and the activation of diverse N-terminal effector domains, including DNA endonucleases, to abrogate infection. Cryo-electron microscopy reveals that Avs sensor domains recognize conserved folds, active-site residues, and enzyme ligands, allowing a single Avs receptor to detect a wide variety of viruses. These findings extend the paradigm of pattern recognition of pathogen-specific proteins across all three domains of life. - -**Gao, L. et al. Diverse enzymatic activities mediate antiviral immunity in prokaryotes. Science 369, 1077-1084 (2020).** -Bacteria and archaea are frequently attacked by viruses and other mobile genetic elements and rely on dedicated antiviral defense systems, such as restriction endonucleases and CRISPR, to survive. The enormous diversity of viruses suggests that more types of defense systems exist than are currently known. By systematic defense gene prediction and heterologous reconstitution, here we discover 29 widespread antiviral gene cassettes, collectively present in 32% of all sequenced bacterial and archaeal genomes, that mediate protection against specific bacteriophages. These systems incorporate enzymatic activities not previously implicated in antiviral defense, including RNA editing and retron satellite DNA synthesis. In addition, we computationally predict a diverse set of other putative defense genes that remain to be characterized. These results highlight an immense array of molecular functions that microbes use against viruses. - +:: \ No newline at end of file diff --git a/content/2.defense-systems/paris.md b/content/2.defense-systems/paris.md index fc6d7898..7f57f047 100644 --- a/content/2.defense-systems/paris.md +++ b/content/2.defense-systems/paris.md @@ -50,11 +50,11 @@ Paris type II merge system in _Desulfovibrio desulfuricans_ (GCF\__000025705.1). ## References -::references-list +::article-doi-list --- items: - 10.1101/2021.01.21.427644 - 10.1093/nar/gkaa290 - 10.1016/0022-2836(75)90083-2 --- -:: +:: \ No newline at end of file diff --git a/pages/[...slug].vue b/pages/[...slug].vue index e0c2b132..9c9bf619 100644 --- a/pages/[...slug].vue +++ b/pages/[...slug].vue @@ -4,6 +4,8 @@ <v-card flat color="transparent" max-width="1280"> <v-card-text> <ContentDoc /> - </v-card-text> </v-card></v-col> + </v-card-text> + </v-card></v-col> </v-row> </template> + -- GitLab