# install dependencies
$ yarn install
# serve with hot reload at localhost:3000
$ yarn dev
# build for production and launch server
$ yarn build
$ yarn start
# generate static project
$ yarn generate
For detailed explanation on how things work, check out Nuxt.js docs.
We will be using non dark mode for now but it's a matter of choice if you want to make it dark you can just put it to true, now after you change the theme to light then change the content in layouts/default.vue :
<template><v-app><nuxt/></v-app></template>
After you finish filling the content inside layouts/default.vue, go to pages/index.vue and write this code, to create our homepage :
Here you can see that index.vue use Home as their base component, let's now create our Home component, create components/Home.vue then write code like this :
<template><div:class="['mx-5', 'my-5']"><v-rowjustify="center"><div:class="[`text-h1`, 'text-center']"v-text="'Open Source Marketplace'"></div></v-row><v-rowjustify="center"><div:class="[`text-h3`, 'px-5', 'text-center', 'my-5']"v-text="'Here you can buy or sell open source repo'"></div></v-row><v-rowjustify="center":class="['my-2']"><v-btn:class="['my-2']"color="info"elevation="2"v-show="login"href="/dashboard">DASHBOARD</v-btn><v-btn:class="['my-2']"color="info"elevation="2"href="/login"v-show="!login">LOGIN</v-btn><v-btn:class="['my-2', 'mx-2']"color="error"elevation="2"v-show="login"@click="logout">LOGOUT</v-btn></v-row><v-row><v-cardclass="mx-auto my-12"max-width="374":key="index"v-for="(item, index) in forSale"><v-imgheight="250":src="item.openGraphImageUrl"></v-img><v-card-title>{{item.name}}</v-card-title><v-card-text><div>{{item.description}}</div></v-card-text><v-dividerclass="mx-4"></v-divider><v-card-actions><v-flex>$ {{item.amount}}</v-flex><v-flexv-if="item.username !== username && !item.owned"><divclass="d-flex justify-end"><v-btn:disabled="disabled"class="d-flex justify-end"color="deep-purple lighten-2"@click="buyNow(item._id)"text>
Buy Now
</v-btn></div></v-flex><v-flexv-if="item.username === username || item.owned"><divclass="d-flex justify-end"><v-btn:disabled="disabled"class="d-flex justify-end"color="deep-purple lighten-2":href="item.url"target="_blank"text>
GO TO URL
</v-btn></div></v-flex></v-card-actions></v-card></v-row></div></template><scriptlang="ts">importCookiesfrom'js-cookie'import{Component,Vue,Prop}from'nuxt-property-decorator'import{configs}from'@/utils/configs.js'@ComponentexportdefaultclassMyStoreextendsVue{@Prop({required:true})readonlylogin!:booleanpublicforSale:Array<object>=[]publicusername:string=''publicdisabled:boolean=falsepublicbuy_paypal_url:string=""logout(){Cookies.remove('token')window.location.reload()}asyncmounted(){console.log(configs)consttoken=Cookies.get('token')constownedRepoUrl=configs.get_owned_repo_urlconsturl=configs.for_sale_repo_urltry{const{data}=awaitthis.$axios.get(`${url}?token=${token}`)constownedRepo=awaitthis.$axios.get(`${ownedRepoUrl}?token=${token}`)this.forSale=data.data.data.map((a:any)=>{if(ownedRepo.data.data.filter((b:any)=>b.owner_username===a.username&&a.name===b.name).length>0){a.owned=truereturna}else{returna}})this.username=data.data.username}catch(e){console.log(e.message)}}asyncbuyNow(_id:any){this.disabled=true;consttoken=Cookies.get('token')consturl=<string>configs.buy_paypal_url;constres=awaitthis.$axios.post(url,{_id,token})if(res.data){constlink=res.data.result.links.filter((a:any)=>a.rel==="approve")[0].hrefwindow.location.href=link;}else{this.disabled=false;alert("error")}}}</script>
And then you will got this as a homepage :
Go to nuxt.config.js and add server object
importcolorsfrom'vuetify/es5/util/colors'exportdefault{// Target (https://go.nuxtjs.dev/config-target)server:{port:8080,// default: 3000host:'0.0.0.0'// default: localhost},target:'server',env:{github_client_id:process.env.github_client_id,paypal_client_id:process.env.paypal_client_id,url:process.env.url,prefix:process.env.prefix,},// Global page headers (https://go.nuxtjs.dev/config-head)head:{titleTemplate:'%s ',title:'Open Source Marketplace',meta:[{charset:'utf-8'},{name:'viewport',content:'width=device-width, initial-scale=1'},{hid:'description',name:'description',content:''},],link:[{rel:'icon',type:'image/x-icon',href:'/favicon.ico'}],},// Global CSS (https://go.nuxtjs.dev/config-css)css:[],// Plugins to run before rendering page (https://go.nuxtjs.dev/config-plugins)plugins:[],// Auto import components (https://go.nuxtjs.dev/config-components)components:true,// Modules for dev and build (recommended) (https://go.nuxtjs.dev/config-modules)buildModules:[// https://go.nuxtjs.dev/typescript'@nuxt/typescript-build',// https://go.nuxtjs.dev/vuetify'@nuxtjs/vuetify','@nuxtjs/dotenv'],// Modules (https://go.nuxtjs.dev/config-modules)modules:[// https://go.nuxtjs.dev/axios'@nuxtjs/axios',],// Axios module configuration (https://go.nuxtjs.dev/config-axios)axios:{},// Vuetify module configuration (https://go.nuxtjs.dev/config-vuetify)vuetify:{defaultAssets:{icons:'fa'},customVariables:['~/assets/variables.scss'],theme:{dark:false,themes:{dark:{primary:colors.blue.darken2,accent:colors.grey.darken3,secondary:colors.amber.darken3,info:colors.teal.lighten1,warning:colors.amber.base,error:colors.deepOrange.accent4,success:colors.green.accent3,},},},},// Build Configuration (https://go.nuxtjs.dev/config-build)build:{},}
Create a login page go to pages/login.vue to create a login form that can login to github
<template><v-rowjustify="center"align="center"><v-card><v-card-text><v-row:class="['my-3','mx-3','text-h4']">LOGIN USING YOUR GITHUB ACCOUNT</v-row><v-rowalign="center"justify="center"><v-btn@click="login_github"><v-iconclass="mx-2 my-2">fab fa-github</v-icon>LOGIN</v-btn></v-row></v-card-text></v-card></v-row></template><scriptlang="ts">import{Component,Vue}from'nuxt-property-decorator'import{configs}from'@/utils/configs.js'@ComponentexportdefaultclassMyStoreextendsVue{login_github(){window.location.href="https://github.com/login/oauth/authorize?scope=repo&client_id="+configs.github_client_id}}</script>
Notice that we added configs.github_client_id you can get that by creating oauth apps in github developer setting https://github.com/settings/developers create new oauth apps then copy paste the github client id there,now let's create our environment variable create a folder called utils and then create a file called configs.js this will be our global configuration to get variable like github_client_id, github_client_secret etc.
Create a dashboard component to make it more easy to maintain late go ahead and create components/Dashboard.vue and write this code :
<template><v-container><v-rowjustify="space-between"><v-colcols="4"class="text-h4 font-weight-bold"><ahref="/"style="text-decoration: none; color: black">Home</a></v-col><v-colcols="4"class="d-flex justify-end"><v-btn@click="logout">LOGOUT</v-btn></v-col></v-row><DashboardInfo:disabled="disabled":username="username":profilePhoto="profilePhoto":paypalToken="paypalToken":paypalBalance="paypalBalance"@disconnect="disconnectPaypal"@connect="connectPaypal"/><v-rowjustify="space-between"><v-colcols="4"class="text-h4 font-weight-bold">For Sale Repo List</v-col></v-row><DashboardForSale:disabled="disabled":ownedRepo="false":amountRefresh="amountRefresh"@get-all-repo="getAllRepo":listRepo="forSale":paypalToken="paypalToken"@sell-repo="sellRepo($event.name, $event.amount)"@unlist-repo="unlistRepo($event.repo_id)"/><v-rowjustify="space-between"><v-colcols="4"class="text-h4 font-weight-bold">Owned Repo</v-col></v-row><DashboardOwned:amountRefresh="amountRefresh":disabled="disabled":ownedRepo="true":paypalToken="paypalToken":listRepo="ownedRepo"/><DashboardRepoAll:disabled="disabled"@list-repo="listRepo($event.item)"@get-all-repo="getAllRepo($event.after_, $event.before_)":pageInfo_="pageInfo_":dialog="dialog":allRepo="allRepo"/><v-snackbarv-model="snackbarAmount">
the amount shouldn't be negative or zero
</v-snackbar></v-container></template><scriptlang="ts">importCookiesfrom'js-cookie'importDashboardInfofrom'@/components/dashboard_components/DashboardInfo.vue'importDashboardForSalefrom'@/components/dashboard_components/DashboardForSale.vue'importDashboardOwnedfrom'@/components/dashboard_components/DashboardOwned.vue'importDashboardRepoAllfrom'@/components/dashboard_components/DashboardRepoAll.vue'import{Component,Vue,Prop}from'nuxt-property-decorator'import{configs}from'@/utils/configs.js'@Component({components:{DashboardInfo,DashboardForSale,DashboardOwned,DashboardRepoAll,},})exportdefaultclassMyStoreextendsVue{@Prop({required:true})readonlylogin!:booleanpublicdialog:boolean=falsepublicusername:string=''publicprofilePhoto:string=''publicsnackbarAmount:boolean=falsepublicpaypalToken:boolean=falsepublicforSale:Array<object>=[]publicallRepo:Array<object>=[]publicownedRepo:Array<object>=[]publicpaypalBalance:number=0publicamountRefresh:number=0publicdisabled:boolean=falsepublicpageInfo_:object={hasPreviousPage:false,hasNextPage:false,startCursor:"",endCursor:""}logout(){Cookies.remove('token')window.location.href='/'}asynccreated(){// if (!this.login) window.location.href = '/'this.disabled=trueconsttoken=Cookies.get('token')consturl=configs.get_profile_urlconstforSaleUrl=configs.get_for_sale_urlconstownedRepoUrl=configs.get_owned_repo_urlconstgetPaypalUrl=configs.get_paypal_urlconstprofile=awaitthis.$axios.get(`${url}?token=${token}`)this.username=profile.data.data.loginthis.profilePhoto=profile.data.data.avatarUrlconstforSale=awaitthis.$axios.get(`${forSaleUrl}?token=${token}`)this.forSale=forSale.data.dataconstownedRepo=awaitthis.$axios.get(`${ownedRepoUrl}?token=${token}`)this.ownedRepo=ownedRepo.data.dataconstpaypalToken=awaitthis.$axios.get(`${getPaypalUrl}?token=${token}`)if(paypalToken.data.status&&!paypalToken.data.data.disconnect){this.paypalToken=truethis.paypalBalance=paypalToken.data.data.amount}this.disabled=false}asyncgetAllRepo(after_:string,before_:string):Promise<void>{this.disabled=trueconsttoken=Cookies.get('token')consturl=configs.get_all_repo_urlif(this.allRepo.length===0){const{data}=awaitthis.$axios.get(`${url}?token=${token}`)this.allRepo=data.data.nodes.map(({...other})=>(this.forSale.filter(({repo_id}:any)=>repo_id===other.id).length>0?{added:true,...other}:{...other}))console.log(this.allRepo)this.pageInfo_=data.data.pageInfo}elseif(typeofafter_==="string"||typeofbefore_==="string"){const{data}=awaitthis.$axios.get(`${url}?token=${token}${before_?`&before=${before_}`:''}${after_?`&after=${after_}`:''}`)this.allRepo=data.data.nodes.map(({...other})=>(this.forSale.filter(({repo_id}:any)=>repo_id===other.id).length>0?{added:true,...other}:{...other}))this.pageInfo_=data.data.pageInfo}this.dialog=truethis.disabled=false}asyncsellRepo(name:string,amount:number){// console.log(amount)this.disabled=trueif(Number(amount)===0||Number(amount)<0||!amount){this.snackbarAmount=truethis.disabled=falsereturn}else{consttoken=Cookies.get('token')consturl=configs.sell_repo_urlconst{data}=awaitthis.$axios.post(`${url}?token=${token}`,{name,amount,})this.amountRefresh=0this.forSale=data.data}this.disabled=false}asynclistRepo(item:object):Promise<void>{this.disabled=trueconsttoken=Cookies.get('token')consturl=configs.list_repo_urlconst{data}=awaitthis.$axios.post(`${url}?token=${token}`,{item})this.forSale=data.datathis.dialog=falsethis.disabled=false}asyncunlistRepo(id:string){this.disabled=trueconsttoken=Cookies.get('token')consturl=configs.unlist_repo_urlconst{data}=awaitthis.$axios.post(`${url}?token=${token}`,{id})this.forSale=data.datathis.disabled=false}asyncconnectPaypal(){if(this.username.trim()!==''){window.location.href=`https://www.sandbox.paypal.com/connect/?flowEntry=static&client_id=${configs.paypal_client_id}&response_type=code&scope=email&redirect_uri=${configs.redirect_uri_paypal}`}else{alert('please wait until username shown')}}asyncdisconnectPaypal(){this.disabled=trueif(this.username.trim()!==''){consturl=configs.disconnect_paypal_urlconsttoken=Cookies.get('token')awaitthis.$axios.post(`${url}?token=${token}`)this.paypalToken=false}else{alert('please wait until username shown')}this.disabled=falseif(this.forSale.length>0){this.getforSale()}}asyncgetforSale(){this.disabled=trueconsttoken=Cookies.get('token')consturl=configs.get_for_sale_urlconst{data}=awaitthis.$axios.get(`${url}?token=${token}`)this.forSale=data.datathis.disabled=false}}</script>
Inside Dashboard.vue component if you notice there is four more component inside the Dashboard.vue component we make that so that the component is more modular and easy to maintain for later use, now let's go ahead and create the first Dashboard.vue modular component components/dashboard_components/DashboardInfo.vue we will use this to get an info of our paypal balance and github username :
After that go ahead and create our second modular component components/dashboard_components/DashboardForSale.vue we will use this component to show our repo that we can sell :
Finally add components/dashboard_components/DashboardRepoAll.vue to show all our repo from our github :
<template><v-rowjustify="center"><v-dialogv-model="dialog"max-width="600px"><v-card><v-card-title><spanclass="headline">Choose Your Repo To Sell</span></v-card-title><v-card-text><v-cardclass="mx-auto"max-width="344"outlined:key="index"v-for="(item, index) in allRepo"><v-list-itemthree-line><v-list-item-content><divclass="overline mb-4">{{item.isPrivate?"PRIVATE":"PUBLIC"}}</div><v-list-item-titleclass="headline mb-1">{{item.name}}</v-list-item-title><v-list-item-subtitle>{{item.description}}</v-list-item-subtitle></v-list-item-content><v-list-item-avatartilesize="80"color="grey"><v-img:src="item.openGraphImageUrl"/></v-list-item-avatar></v-list-item><v-card-actions><v-btnv-if="!item.added"roundedcolor="blue":disabled="disabled"@click="listRepo(item)">
LIST REPO
</v-btn></v-card-actions></v-card><v-rowjustify="center"class="mt-2"><v-btnclass="mx-2"fabdarklargecolor="cyan":disabled="!pageInfo_.hasPreviousPage||disabled"@click="getAllRepo(undefined,pageInfo_.startCursor)"><v-icon>
fas fa-arrow-left
</v-icon></v-btn><v-btnclass="mx-2"fabdarklargecolor="cyan":disabled="!pageInfo_.hasNextPage||disabled"@click="getAllRepo(pageInfo_.endCursor,undefined)"><v-icon>
fas fa-arrow-right
</v-icon></v-btn></v-row></v-card-text></v-card></v-dialog></v-row></template><scriptlang="ts">import{Component,Vue,Prop,Emit}from'nuxt-property-decorator'@ComponentexportdefaultclassMyStoreextendsVue{@Prop({required:true})readonlydialog!:boolean@Prop({required:true})readonlyallRepo!:Array<object>@Prop({required:true})readonlypageInfo_!:object@Prop({required:true})readonlydisabled!:boolean@Emit()getAllRepo(after_:string,before_:string){return{after_,before_}}@Emit()listRepo(item:object){return{item}}}</script>
Now in order for us to accept the redirect url we need route to save the token that we get from github login create pages/callback.vue in order to do that and write this code :