<template> <div id="page-content-wrapper main-wrapper" class=" flex flex-wrap justify-center mt-14 mb-24 text-2xl tracking-wide font-medium " > <div class="ml-6 mr-6"> <!-- <p class="mt-8"> <b> CD-CODE is a comprehensive, manually curated database of biomolecular condensates and an encyclopedia of the scientific terms used to describe and characterize those condensates. {{ isDev ? "(Dev)" : "" }} </b> <br /> <br /> </p> --> <div class="grid grid-cols-3 lg:grid-cols-4 gap-4"> <div class="col-span-2 lg:col-span-3"> <div class=" flex flex-col space-y-4 md:grid md:grid-cols-2 md:gap-x-4 h-auto " > <div class="border md:col-span-2 border-gray-300 rounded-lg p-6"> <form class="form-horizontal" autocomplete="off" onSubmit="return false;" > <div class="row"> <label class="control-label col-sm-2" /> <div class="col-sm-4 input-sm mb-4"> <input id="protein" v-model="pick" class="radio-inline" type="radio" value="protein" > <label class="radio-label text-2xl font-medium" for="protein" >Protein</label> <input id="condensate" v-model="pick" class="radio-inline" type="radio" value="condensate" > <label class="radio-label text-2xl font-medium" for="condensate" >Condensate</label> </div> </div> <div class="form-group"> <label class="control-label font-medium col-sm-2" for="species" >Species</label> <div class="col-sm-8"> <fetch-species> <template slot-scope="{ response, loading }"> <div v-if="loading"> Loading... </div> <div v-else> <select id="species" v-model="species" class=" bg-white px-3 py-4 rounded-lg border border-gray-400 w-full text-gray-700 outline-none bg-transparent border-b hover:border-blue-700 " > <option v-for="item in removeNullItems(response.data)" :key="item.tax_id" > {{ item._id && item._id !== 0 ? `${item._id} (${item.tax_id})` : "All" }} </option> </select> </div> </template> </fetch-species> </div> </div> <div class="row"> <label class="control-label font-medium col-sm-2" for="keyword" >Search</label> <div class="col-sm-8"> <vue-simple-suggest v-model="selected" :list="getSuggestionList" display-attribute="name" @select="onSelect" > <!-- Filter by input text to only show the matching results --> <input id="keyword" v-model="keyword" class=" bg-white py-4 px-4 w-full rounded-lg text-gray-700 bg-transparent border border-gray-500 hover:border-gray-700 " type="text" :placeholder="placeholder" > <div slot="suggestion-item" slot-scope="{ suggestion: suggestionItem }" > <span v-if="suggestionItem.type === 'protein'" >{{ suggestionItem.gene_name }} ({{ suggestionItem.id }}): {{ suggestionItem.species_name }}</span> <span v-else-if="suggestionItem.type === 'condensate'" >{{ suggestionItem.id }}: {{ suggestionItem.species_name }}</span> <span v-else-if="suggestionItem.type === 'search'" >Search for <b>{{ suggestionItem.id.replace(/\#/g, "") }}</b></span> </div> </vue-simple-suggest> </div> <div class="col-sm-2"> <button class=" bg-blue-500 font-bold rounded-lg py-4 px-5 text-white hover:bg-blue-700 float-left " type="submit" @click="searchWithKeyword" > Search </button> </div> </div> <div class="form-group"> <label class="col-sm-2" /> <div class="col-sm-8 input-sm"> <span style="float: right" class="font-medium" > Examples: <span class="text-pink-base font-medium"> <router-link to="/protein_example">UNE6</router-link>, <router-link to="/condensate_example" >nucleolus__3702</router-link> </span> </span> </div> </div> </form> <!--<div>{{require('lodash').map(this.$store.getters['Param/proteinList'], d => d.proteinName)}}</div>--> <!--<tags-input v-model="proteinNameList"/>--> <!--<div>--> <!--<router-link to="/endo2" tag="button">Overview</router-link>--> <!--<router-link to="/pheno_profile" tag="button">Phenotype Profiles</router-link>--> <!--</div>--> <div> <Search ref="search"> <template slot-scope="{ response, loading }"> <div v-if="loading"> Loading... </div> <div v-else-if="response"> <div v-show="response.count === 0"> No results! </div> <data-table v-show="response.count > 0" id="dataTable" :category="searchPick" :data="response.data" :keyword="keyword" /> </div> </template> </Search> </div> </div> <div class="border p-8 border-gray-300 rounded-lg"> <!-- <h4 class="round mb-8">All Contributors</h4> <contributor-list-table id="all" entity="all" /> --> <!-- <img src="@/assets/figure_1a.png" class=" object-scale-down transition duration-500 ease-in-out transform hover:-translate-y-1 hover:scale-110 " alt="Figure" width="500" height="600" /> --> <p class="text-xl md:text-2xl lg:text-3xl text-justify"> CD-CODE (CrowDsourcing COndensate Database and Encyclopedia) is a comprehensive, semi-manually curated crowdsourcing database of biomolecular condensates and their constituents as well as an encyclopedia for the scientific terms used to describe them. Biomolecular condensates are membrane-less organelles that are formed by liquid-liquid phase separation(LLPS). In cells, phase separation is driven by driver proteins and nucleic acid, which recruit client molecules into the condensate. CD-CODE allows for the dynamic and fast addition, and review of new condensates and proteins by contributing users. CD-CODE is a semi-manually curated and annotated database that aggregates information from primary literature and other protein and LLPS databases. {{ isDev ? "(Dev)" : "" }} </p> <button class=" bg-blue-500 font-bold rounded-lg py-4 px-5 text-white hover:bg-blue-700 float-left " @click="$router.push('/about')" > Read more </button> </div> <div class="border p-8 border-gray-300 rounded-lg"> <div class="flex justify-center"> <img src="@/assets/figures/Figure_1a_v2.png" class="object-contain md:w-full lg:w-4/5 rounded-lg" alt="Figure" > </div> <p class="text-xl p-4 mt-2 text-justify lg:text-3xl"> Schematic Workflow of CD-CODE. CD-CODE contains curated data about 225 condensates and 10571 proteins which can be viewed by users. Contributors can edit the existing data and add more information to the database which will be evaluated and confirmed by CD-CODE mainatainers. Moreover, maintainers keep the database up to date by manually curating newly released research. </p> </div> </div> </div> <!-- <img src="@/assets/CD-CODE_blobs.svg" alt="Logo" /> --> <div class="border border-gray-300 rounded-lg"> <a class="twitter-timeline" data-height="1000" href="https://twitter.com/agnestothp?ref_src=twsrc%5Etfw" >Tweets by agnestothp</a> </div> <div class=" border col-span-3 md:col-span-4 lg:col-span-4 border-gray-300 rounded-lg p-8 " > <h2 class="mb-10 text-3xl text-center"> All Contributors </h2> <contributor-list-table id="all" entity="all" /> </div> <div class=" border col-span-3 md:col-span-4 lg:col-span-4 border-gray-300 rounded-lg p-8 " > <h2 class="mb-10 text-3xl text-center"> CD-CODE is brought to you by </h2> <the-team-list /> </div> </div> </div> </div> </template> <script> import Search from '@/components/Search.vue'; import DataTable from '@/components/DataTable.vue'; import FetchSpecies from '@/components/DDCODE/fetchSpecies.vue'; import VueSimpleSuggest from 'vue-simple-suggest'; import ContributorListTable from './ContributorListTable.vue'; import TheTeamList from './Team/TheTeamList.vue'; const _ = require('lodash'); const apikey = require('./js/const').apikey; export default { name: 'LandingPage', components: { Search, FetchSpecies, DataTable, VueSimpleSuggest, ContributorListTable, TheTeamList, }, props: { msg: String, }, data() { return { selected: '', keyword: '', species: 'All', speciesOption: '', speciesOptions: undefined, searchKeyword: '', pick: 'protein', searchPick: '', placeholder: 'Enter Uniprot ID, gene name, or protein name', suggestion: '', isDev: process.env.NODE_ENV === 'development', }; }, computed: { jwt: function () { return this.$store.getters['User/jwt']; }, userData: function () { return this.$store.getters['User/userData']; }, getRole: function () { return this.$store.getters['User/userRole']; }, proteinNameList: { get() { return _.map(this.proteinList, (d) => { return { text: d.uniprot_id }; }); }, set(obj) { const idx = this.proteinList.findIndex( (d) => d.uniprot_id === obj.tag.text ); this.$store.dispatch('Param/removeProtein', idx); obj.deleteTag(); // console.log(this.$store.getters['Param/proteinList']) }, }, }, watch: { selected: { handler: function (key) { this.keyword = key; // console.log(key); // this.searchWithKeyword(); }, deep: true, }, pick: { handler: function (val) { if (val === 'protein') { this.placeholder = 'Enter Uniprot ID, gene name, or protein name'; } else if (val === 'condensate') { this.placeholder = 'Enter condensate name'; } }, }, suggestion: { handler: function (val) { console.log(val); // this.searchWithKeyword(); }, }, }, mounted() { // console.log(this.keyword) // console.log(this.$route) // console.log(this.$route.query) // console.log(this.$route.query.q) this.search(this.$route.query.q, this.$route.query.t, this.$route.query.s); window.twttr = (function (d, s, id) { var js, fjs = d.getElementsByTagName(s)[0], t = window.twttr || {}; if (d.getElementById(id)) return t; js = d.createElement(s); js.id = id; js.src = 'https://platform.twitter.com/widgets.js'; fjs.parentNode.insertBefore(js, fjs); t._e = []; t.ready = function (f) { t._e.push(f); }; return t; })(document, 'script', 'twitter-wjs'); if (window.twttr.widgets) { window.twttr.widgets.load( document.getElementsByClassName('twitter-timeline') ); } }, methods: { onSelect(item) { if (item.type === 'protein') { this.keyword = '(' + item.id + ')'; } else if (item.type === 'condensate') { this.keyword = '(' + item.canonical_id + ')'; } else if (item.type === 'search') { this.keyword = item.id.replace(/\#/g, ''); } else { this.keyword = item.id; } this.searchWithKeyword(); }, removeNullItems(data) { const vm = this; if (!vm.speciesOptions) { const options = _.filter(data, (d) => d._id !== null); if (vm.speciesOption) { options.forEach((item) => { if (item.tax_id === vm.speciesOption) { vm.species = item._id && item._id !== 0 ? `${item._id} (${item.tax_id})` : 'All'; } }); } vm.speciesOptions = options; } return vm.speciesOptions; }, getSuggestionList() { const vm = this; const query = vm.keyword; let host = vm.isDev ? require('./js/const').devHost : require('./js/const').host; const taxId = vm.species === 'All' ? 'all' : /\((\d+)\)$/gm.exec(vm.species)[1]; let url = vm.species === 'All' ? `${host}/${vm.pick}s?fields=gene_name,name,uniprot_id,species_name&query=${query}&size=20000` : `${host}/${vm.pick}s?fields=gene_name,name,uniprot_id,species_name&query=${query}&species_tax_id=${taxId}&size=10000`; // console.log(process.env.VUE_APP_TITLE) // console.log(process.env.VUE_APP_API_KEY) return fetch(url, { method: 'GET', mode: 'cors', cache: 'no-cache', headers: { Authorization: `Bearer ${apikey}`, }, }) .then((response) => response.json()) .then((json) => { // console.log(json.data); const ret = _.uniqBy( _.map(json.data, (c) => { if (c.gene_name) { return { id: c.uniprot_id, species_name: c.species_name, gene_name: c.gene_name, name: c.name, type: 'protein', }; } else { return { id: c.name, species_name: c.species_name, canonical_id: c.canonical_id, type: 'condensate', }; } }), 'id' ); if (ret.length > 9) { ret.splice(9, 0, { id: '#' + query, type: 'search' }); } else { ret.push({ id: '#' + query, type: 'search' }); } // console.log(ret); return ret; }); }, searchWithKeyword() { const vm = this; // console.log(/\((\d+)\)$/gm.exec(vm.species)) // console.log(vm.species); const taxId = vm.species === 'All' ? 'all' : vm.species === 'Chimeras' ? 'null' : /\((\d+)\)$/gm.exec(vm.species)[1]; const page = 1; // console.log(`http://${host}/proteins?query=${vm.keyword}&species_tax_id=${taxId}&page=${page}`) // vm.searchKeyword = vm.keyword; // console.log(vm.pick) // vm.searchPick = vm.pick; vm.$router.replace({ name: 'home', query: { q: vm.keyword, t: vm.pick, s: taxId, }, }); vm.$router.push({ name: 'search', query: { q: vm.keyword, t: vm.pick, s: taxId, }, }); // vm.search(this.$route.query.q, this.$route.query.t, this.$route.query.s) // /* eslint-disable no-console */ // console.log(this.searchKeyword) }, search(q, t, s) { const vm = this; // const page = 1; // console.log(`http://${host}/proteins?query=${vm.keyword}&species_tax_id=${taxId}&page=${page}`) if (q) { vm.keyword = q; vm.searchKeyword = vm.keyword; } if (s) { vm.speciesOption = s; } // console.log(vm.pick) if (t) { vm.searchPick = t; vm.pick = t; } // if (t === 'protein') { // vm.$refs.search.fetchProteinList(q, s); // } else if (t === 'condensate') { // vm.$refs.search.fetchCondensateList(q, s); // } // /* eslint-disable no-console */ // console.log(this.searchKeyword) }, }, }; </script> <!-- Add "scoped" attribute to limit CSS to this component only --> <style scoped> @import url("~@/assets/bootstrap.css"); @import url("~@/assets/datatable.css"); @import url("~@/assets/vue-simple-suggest-styles.css"); .main { margin: 1.5rem; } h3 { margin: 40px 0 0; } input[type="radio"] { margin: 4px; } .radio-label { margin-left: 0px; margin-right: 5px; } .center-image { display: -webkit-box; -webkit-box-pack: center; /* justify-content */ -webkit-box-align: center; /* align-items */ } </style>