1단계 - Nuxtjs를 사용하여 프런트엔드 만들기
149587 단어 dohackathon
캣플립 / 오픈소스-마켓플레이스-프론트엔드
할일 버튼 배치
빌드 설정
# 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.
First of all create a nuxtjs application by using this command :
yarn create nuxt-app opensource-marketplace-frontend
다음 설정을 사용하여 애플리케이션을 생성합니다.
? Project name: frontend
? Programming language: TypeScript
? Package manager: Yarn
? UI framework: Vuetify.js
? Nuxt.js modules: Axios
? Linting tools: ESLint, Prettier
? Testing framework: Jest
? Rendering mode: Universal (SSR / SSG)
? Deployment target: Static (Static/JAMStack hosting)
? Development tools: (Press <space> to select, <a> to toggle all, <i> to invert selection)
? Continuous integration: None
? Version control system: None
완료 후
yarn dev
를 사용하여 앱을 실행하면 다음 화면이 표시됩니다.이제
nuxt.config.js
로 이동하여 아래에서 이 줄을 검색하고 dark
를 false
로 변경합니다....
vuetify: {
defaultAssets: {icons: 'fa'},
customVariables: ['~/assets/variables.scss'],
theme: {
dark: false,
themes: {
dark: {
...
지금은 어두운 모드가 아닌 모드를 사용하지만 원하는 경우 선택의 문제입니다
dark
. 이제 테마를 밝게 변경한 후 true
에서 콘텐츠를 변경하면 됩니다. :<template>
<v-app >
<nuxt/>
</v-app>
</template>
layouts/default.vue
안의 내용을 다 채운 후 layouts/default.vue
로 이동하여 다음 코드를 작성하여 홈페이지를 만듭니다.<template>
<Home :login="login" />
</template>
<script lang="ts">
import Cookies from 'js-cookie'
import Home from '@/components/Home.vue'
import { Component, Vue } from 'nuxt-property-decorator'
@Component({
components: {
Home,
},
})
export default class MyStore extends Vue {
public login: boolean =false;
mounted(){
this.login=Cookies.get('token') && Cookies?.get('token')?.trim() !== ''
? true
: false
}
}
</script>
여기에서
pages/index.vue
가 index.vue
를 기본 구성 요소로 사용하는 것을 볼 수 있습니다. 이제 Home
구성 요소를 만들고 Home
를 만든 다음 다음과 같은 코드를 작성해 보겠습니다.<template>
<div :class="['mx-5', 'my-5']">
<v-row justify="center">
<div
:class="[`text-h1`, 'text-center']"
v-text="'Open Source Marketplace'"
></div>
</v-row>
<v-row justify="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-row justify="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-card
class="mx-auto my-12"
max-width="374"
:key="index"
v-for="(item, index) in forSale"
>
<v-img height="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-divider class="mx-4"></v-divider>
<v-card-actions>
<v-flex>$ {{ item.amount }}</v-flex>
<v-flex v-if="item.username !== username && !item.owned"
><div class="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-flex v-if="item.username === username || item.owned"
><div class="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>
<script lang="ts">
import Cookies from 'js-cookie'
import { Component, Vue, Prop } from 'nuxt-property-decorator'
import {configs} from '@/utils/configs.js'
@Component
export default class MyStore extends Vue {
@Prop({ required: true }) readonly login!: boolean
public forSale: Array<object> = []
public username: string = ''
public disabled: boolean = false
public buy_paypal_url: string = ""
logout() {
Cookies.remove('token')
window.location.reload()
}
async mounted() {
console.log(configs)
const token = Cookies.get('token')
const ownedRepoUrl = configs.get_owned_repo_url
const url = configs.for_sale_repo_url
try {
const { data } = await this.$axios.get(`${url}?token=${token}`)
const ownedRepo = await this.$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 = true
return a
} else {
return a
}
})
this.username = data.data.username
} catch (e) {
console.log(e.message)
}
}
async buyNow(_id:any) {
this.disabled=true;
const token = Cookies.get('token')
const url=<string>configs.buy_paypal_url;
const res = await this.$axios.post(url, { _id, token })
if (res.data) {
const link=res.data.result.links.filter((a:any)=>a.rel==="approve")[0].href
window.location.href=link;
}else{
this.disabled=false;
alert("error")
}
}
}
</script>
그러면 다음과 같은 홈페이지가 표시됩니다.
components/Home.vue
로 이동하여 nuxt.config.js
개체를 추가합니다.import colors from 'vuetify/es5/util/colors'
export default {
// Target (https://go.nuxtjs.dev/config-target)
server: {
port: 8080, // default: 3000
host: '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: {},
}
로그인 페이지 만들기
server
로 이동하여 github에 로그인할 수 있는 로그인 양식을 만듭니다.<template>
<Login />
</template>
<script lang="ts">
import Login from '@/components/Login.vue'
import { Component, Vue } from 'nuxt-property-decorator'
@Component({
components: {
Login,
},
})
export default class MyStore extends Vue {}
</script>
pages/login.vue
에서 구성 요소를 생성합니다.<template>
<v-row justify="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-row align="center" justify="center">
<v-btn @click="login_github"><v-icon class="mx-2 my-2">fab fa-github</v-icon>LOGIN</v-btn>
</v-row>
</v-card-text>
</v-card>
</v-row>
</template>
<script lang="ts">
import { Component, Vue } from 'nuxt-property-decorator'
import {configs} from '@/utils/configs.js'
@Component
export default class MyStore extends Vue {
login_github(){
window.location.href="https://github.com/login/oauth/authorize?scope=repo&client_id="+configs.github_client_id
}
}
</script>
추가한
components/Login.vue
github 개발자 설정configs.github_client_id
에서 oauth 앱을 생성하여 얻을 수 있습니다. 새 oauth 앱을 만든 다음 거기에 github 클라이언트 ID를 복사하여 붙여넣습니다. 이제 환경 변수를 만들고 https://github.com/settings/developers
라는 폴더를 만든 다음 utils
라는 파일을 생성합니다. 이것은 github_client_id, github_client_secret 등과 같은 변수를 가져오는 전역 구성이 됩니다.const configs={}
configs.url=process.env.url;
configs.prefix=process.env.prefix;
configs.github_client_id=process.env.github_client_id
configs.paypal_client_id=process.env.paypal_client_id
configs.save_paypal_url=`${configs.url}${configs.prefix}/save-paypal`
configs.buy_paypal_url=`${configs.url}${configs.prefix}/buy-paypal`
configs.for_sale_repo_url=`${configs.url}${configs.prefix}/for-sale-repo`
configs.disconnect_paypal_url=`${configs.url}${configs.prefix}/disconnect-paypal`
configs.redirect_uri_paypal=`${configs.url}${configs.prefix}/paypal-auth`
configs.unlist_repo_url=`${configs.url}${configs.prefix}/unlist-repo`
configs.sell_repo_url=`${configs.url}${configs.prefix}/sell-repo`
configs.get_all_repo_url=`${configs.url}${configs.prefix}/get-all-repo`
configs.get_profile_url=`${configs.url}${configs.prefix}/get-profile`
configs.get_for_sale_url=`${configs.url}${configs.prefix}/get-for-sale-repo`
configs.get_owned_repo_url=`${configs.url}${configs.prefix}/get-owned-repo`
configs.get_paypal_url=`${configs.url}${configs.prefix}/get-paypal`
configs.list_repo_url=`${configs.url}${configs.prefix}/list-repo`
configs.repo_detail_url=`${configs.url}${configs.prefix}/repo-detail`
module.exports={configs}
개발 중에 환경 변수를 쉽게 처리할 수 있도록
configs.js
파일도 필요합니다. 계속해서 다음 값으로 .env
를 생성하십시오.github_client_id=<github_client_id>
paypal_client_id=<paypal_client_id>
url=http://localhost:4000
prefix=
필요에 따라 값을 변경한 후 대시보드를 만든 후
.env
로 이동하여 다음 코드를 작성합니다.<template>
<Dashboard :login="login" />
</template>
<script lang="ts">
import Cookies from 'js-cookie'
import Dashboard from '@/components/Dashboard.vue'
import { Component, Vue } from 'nuxt-property-decorator'
@Component({
components: {
Dashboard,
},
})
export default class MyStore extends Vue {
public login: boolean =false;
mounted(){
this.login=Cookies.get('token') && Cookies?.get('token')?.trim() !== ''
? true
: false
}
}
</script>
나중에 유지 관리하기가 더 쉽도록 대시보드 구성 요소를 생성하고 다음 코드를 생성
pages/dashboard.vue
하고 작성합니다.<template>
<v-container>
<v-row justify="space-between">
<v-col cols="4" class="text-h4 font-weight-bold"
><a href="/" style="text-decoration: none; color: black">Home</a></v-col
>
<v-col cols="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-row justify="space-between">
<v-col cols="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-row justify="space-between">
<v-col cols="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-snackbar v-model="snackbarAmount">
the amount shouldn't be negative or zero
</v-snackbar>
</v-container>
</template>
<script lang="ts">
import Cookies from 'js-cookie'
import DashboardInfo from '@/components/dashboard_components/DashboardInfo.vue'
import DashboardForSale from '@/components/dashboard_components/DashboardForSale.vue'
import DashboardOwned from '@/components/dashboard_components/DashboardOwned.vue'
import DashboardRepoAll from '@/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,
},
})
export default class MyStore extends Vue {
@Prop({ required: true }) readonly login!: boolean
public dialog: boolean = false
public username: string = ''
public profilePhoto: string = ''
public snackbarAmount: boolean = false
public paypalToken: boolean = false
public forSale: Array<object> = []
public allRepo: Array<object> = []
public ownedRepo: Array<object> = []
public paypalBalance: number = 0
public amountRefresh: number = 0
public disabled: boolean = false
public pageInfo_: object = {hasPreviousPage:false,hasNextPage:false,startCursor:"",endCursor:""}
logout() {
Cookies.remove('token')
window.location.href = '/'
}
async created() {
// if (!this.login) window.location.href = '/'
this.disabled = true
const token = Cookies.get('token')
const url = configs.get_profile_url
const forSaleUrl = configs.get_for_sale_url
const ownedRepoUrl = configs.get_owned_repo_url
const getPaypalUrl = configs.get_paypal_url
const profile = await this.$axios.get(`${url}?token=${token}`)
this.username = profile.data.data.login
this.profilePhoto = profile.data.data.avatarUrl
const forSale = await this.$axios.get(`${forSaleUrl}?token=${token}`)
this.forSale = forSale.data.data
const ownedRepo = await this.$axios.get(`${ownedRepoUrl}?token=${token}`)
this.ownedRepo = ownedRepo.data.data
const paypalToken = await this.$axios.get(`${getPaypalUrl}?token=${token}`)
if (paypalToken.data.status && !paypalToken.data.data.disconnect) {
this.paypalToken = true
this.paypalBalance = paypalToken.data.data.amount
}
this.disabled = false
}
async getAllRepo(after_: string, before_: string): Promise<void> {
this.disabled = true
const token = Cookies.get('token')
const url = configs.get_all_repo_url
if (this.allRepo.length === 0) {
const { data } = await this.$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
} else if(typeof after_==="string"||typeof before_==="string"){
const { data } = await this.$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 = true
this.disabled = false
}
async sellRepo(name: string, amount: number) {
// console.log(amount)
this.disabled = true
if (Number(amount) === 0 || Number(amount) < 0 || !amount) {
this.snackbarAmount = true
this.disabled = false
return
} else {
const token = Cookies.get('token')
const url = configs.sell_repo_url
const { data } = await this.$axios.post(`${url}?token=${token}`, {
name,
amount,
})
this.amountRefresh = 0
this.forSale = data.data
}
this.disabled = false
}
async listRepo(item: object): Promise<void> {
this.disabled = true
const token = Cookies.get('token')
const url = configs.list_repo_url
const { data } = await this.$axios.post(`${url}?token=${token}`, { item })
this.forSale = data.data
this.dialog=false
this.disabled = false
}
async unlistRepo(id: string) {
this.disabled = true
const token = Cookies.get('token')
const url = configs.unlist_repo_url
const { data } = await this.$axios.post(`${url}?token=${token}`, { id })
this.forSale = data.data
this.disabled = false
}
async connectPaypal() {
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')
}
}
async disconnectPaypal() {
this.disabled = true
if (this.username.trim() !== '') {
const url = configs.disconnect_paypal_url
const token = Cookies.get('token')
await this.$axios.post(`${url}?token=${token}`)
this.paypalToken = false
} else {
alert('please wait until username shown')
}
this.disabled = false
if (this.forSale.length > 0) {
this.getforSale()
}
}
async getforSale() {
this.disabled = true
const token = Cookies.get('token')
const url = configs.get_for_sale_url
const { data } = await this.$axios.get(`${url}?token=${token}`)
this.forSale = data.data
this.disabled = false
}
}
</script>
components/Dashboard.vue
구성 요소 내부 Dashboard.vue
구성 요소 내부에 4개의 구성 요소가 더 있음을 알게 되면 나중에 사용할 수 있도록 구성 요소를 더 모듈화하고 유지 관리하기 쉽게 만듭니다. 이제 첫 번째Dashboard.vue
모듈 구성 요소를 생성하겠습니다. Dashboard.vue
이것을 사용하여 페이팔 잔액 및 github 사용자 이름 정보를 얻습니다.<template>
<v-row>
<v-card max-width="344" outlined>
<v-list-item three-line>
<v-list-item-content>
<v-list-item-title class="headline mb-1">
Github Username
</v-list-item-title>
<v-list-item-title class="text-h5">{{username}}</v-list-item-title>
</v-list-item-content>
<v-list-item-avatar size="80" color="grey">
<v-img :src="profilePhoto" />
</v-list-item-avatar>
</v-list-item>
</v-card>
<v-card class="mx-5" max-width="344" outlined>
<v-list-item three-line>
<v-list-item-content>
<v-list-item-title class="headline mb-1"> Balance </v-list-item-title>
<v-list-item-title>
<v-row justify="space-between">
<v-col class="font-weight-bold text-h5" v-if="paypalToken">$ {{paypalBalance}}</v-col>
<v-col v-if="paypalToken"><v-btn color="red" :disabled="disabled" @click="disconnect">DISCONNECT PAYPAL</v-btn></v-col>
<v-col v-if="!paypalToken"><v-btn color="blue" :disabled="disabled" @click="connect">CONNECT PAYPAL</v-btn></v-col>
</v-row>
</v-list-item-title>
</v-list-item-content>
</v-list-item>
</v-card>
</v-row>
</template>
<script lang="ts">
import { Component, Vue, Prop,Emit } from 'nuxt-property-decorator'
@Component
export default class MyStore extends Vue {
@Prop({ required: true }) readonly username!: string
@Prop({ required: true }) readonly profilePhoto!: string
@Prop({ required: false }) readonly paypalBalance!: number
@Prop({ required: true }) readonly paypalToken!: boolean
@Prop({ required: true }) readonly disabled!: boolean
@Emit()
connect(){}
@Emit()
disconnect(){}
}
</script>
그런 다음 계속해서 두 번째 모듈 구성 요소
components/dashboard_components/DashboardInfo.vue
를 생성합니다. 이 구성 요소를 사용하여 판매할 수 있는 저장소를 표시합니다.<template>
<div>
<v-row class="mb-2" ><v-btn @click="getAllRepo" :disabled="disabled">SELL REPO</v-btn></v-row
>
<v-row>
<v-card
width="400"
class="mx-2 my-2"
:key="index"
v-for="(item, index) in listRepo"
>
<v-card-title>
<v-list-item class="grow">
<v-list-item-content>
<v-list-item-title>{{ item.name }}</v-list-item-title>
</v-list-item-content>
<v-row align="center" justify="end"> {{item.isPrivate?"Private":"Public"}} </v-row>
</v-list-item>
</v-card-title>
<v-card-text class="text-md font-weight-bold">
<v-list-item>
<v-list-item-content>{{ item.description }}</v-list-item-content>
<v-list-item-avatar tile size="100" color="grey">
<v-img :src="item.openGraphImageUrl" />
</v-list-item-avatar>
</v-list-item>
</v-card-text>
<v-card-action
><v-row class="d-flex align-content-center mx-5">
<v-col cols="5" class="d-flex justify-start align-content-center">
<div
class="d-flex align-center text-h5"
:style="{ height: '100%' }"
v-if="item.sell === 'SELL'&&!ownedRepo"
>
$ {{ item.amount }}
</div>
<v-text-field
v-if="item.sell === 'UNLIST'"
label="Amount"
type="number"
outlined
prefix="$"
:disabled="!paypalToken"
v-model="item.amount"
></v-text-field>
</v-col>
<v-col class="d-flex mt-2 justify-end">
<v-btn
@click="sellRepo(item.name, item.amount)"
color="red"
v-if="item.sell === 'UNLIST'&&!ownedRepo"
:disabled="!paypalToken||disabled"
>SELL</v-btn
><v-btn :disabled="!paypalToken||disabled" v-if="item.sell === 'SELL'&&!ownedRepo" @click="unlistRepo(item.repo_id)"
>UNLIST</v-btn
>
<v-btn v-if="ownedRepo" target="_blank" :href="item.url"
>GO TO URL</v-btn
>
</v-col>
</v-row></v-card-action
>
</v-card>
</v-row>
</div>
</template>
<script lang="ts">
import { Component, Vue, Prop, Emit } from 'nuxt-property-decorator'
@Component
export default class MyStore extends Vue {
@Prop({ required: false }) readonly refreshRepo!: void
@Prop({ required: false }) readonly paypalToken!: boolean
@Prop({ required: true }) readonly listRepo!: Array<object>
@Prop({ required: true }) readonly amountRefresh!: number
@Prop({ required: true }) readonly ownedRepo!: boolean
@Prop({ required: true }) readonly disabled!: boolean
public amount: number=this.amountRefresh
@Emit()
getAllRepo() {
}
@Emit()
sellRepo(name: string, amount: number) {
return { name, amount }
}
@Emit()
unlistRepo(repo_id: string) {
return { repo_id }
}
}
</script>
그런 다음
components/dashboard_components/DashboardForSale.vue
를 추가하여 오픈 소스 마켓플레이스에서 구매한 모든 항목을 확인합니다.<template>
<div>
<v-row class="mb-2" v-if="refreshRepo"
><v-btn @click="getAllRepo" :disabled="disabled">SELL REPO</v-btn></v-row
>
<v-row>
<v-card
width="400"
class="mx-2 my-2"
:key="index"
v-for="(item, index) in listRepo"
>
<v-card-title>
<v-list-item class="grow">
<v-list-item-content>
<v-list-item-title>{{ item.name }}</v-list-item-title>
</v-list-item-content>
<v-row align="center" justify="end"> {{item.isPrivate?"Private":"Public"}}</v-row>
</v-list-item>
</v-card-title>
<v-card-text class="text-md font-weight-bold">
<v-list-item>
<v-list-item-content>{{ item.description }}</v-list-item-content>
<v-list-item-avatar tile size="100" color="grey">
<v-img :src="item.openGraphImageUrl" />
</v-list-item-avatar>
</v-list-item>
</v-card-text>
<v-card-action
><v-row class="d-flex align-content-center mx-5">
<v-col cols="5" class="d-flex justify-start align-content-center">
<div
class="d-flex align-center text-h5"
:style="{ height: '100%' }"
v-if="item.sell === 'SELL'&&!ownedRepo"
>
$ {{ item.amount }}
</div>
<v-text-field
v-if="item.sell === 'UNLIST'"
label="Amount"
type="number"
outlined
prefix="$"
:disabled="!paypalToken"
v-model="amount"
></v-text-field>
</v-col>
<v-col class="d-flex mt-2 justify-end">
<v-btn
@click="sellRepo(item._id, amount)"
color="red"
v-if="item.sell === 'UNLIST'&&!ownedRepo"
:disabled="!paypalToken||disabled"
>SELL</v-btn
><v-btn :disabled="!paypalToken||disabled" v-if="item.sell === 'SELL'&&!ownedRepo" @click="unlistRepo(item._id)"
>UNLIST</v-btn
>
<v-btn v-if="ownedRepo" target="_blank" :href="item.url"
>GO TO URL</v-btn
>
</v-col>
</v-row></v-card-action
>
</v-card>
</v-row>
</div>
</template>
<script lang="ts">
import { Component, Vue, Prop, Emit } from 'nuxt-property-decorator'
@Component
export default class MyStore extends Vue {
@Prop({ required: false }) readonly refreshRepo!: void
@Prop({ required: false }) readonly paypalToken!: boolean
@Prop({ required: true }) readonly listRepo!: Array<object>
@Prop({ required: true }) readonly amountRefresh!: number
@Prop({ required: true }) readonly ownedRepo!: boolean
@Prop({ required: true }) readonly disabled!: boolean
public amount: number=this.amountRefresh
@Emit()
getAllRepo() {
}
@Emit()
sellRepo(_id: string, amount: number) {
return { _id, amount }
}
@Emit()
unlistRepo(_id: string) {
return { _id }
}
}
</script>
마지막으로
components/dashboard_component/DashboardOwned.vue
를 추가하여 github의 모든 저장소를 표시합니다.<template>
<v-row justify="center">
<v-dialog
v-model="dialog"
max-width="600px"
>
<v-card>
<v-card-title>
<span class="headline">Choose Your Repo To Sell</span>
</v-card-title>
<v-card-text>
<v-card
class="mx-auto"
max-width="344"
outlined
:key="index"
v-for="(item, index) in allRepo"
>
<v-list-item three-line>
<v-list-item-content>
<div class="overline mb-4">
{{item.isPrivate?"PRIVATE":"PUBLIC"}}
</div>
<v-list-item-title class="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-avatar
tile
size="80"
color="grey"
><v-img :src="item.openGraphImageUrl"/></v-list-item-avatar>
</v-list-item>
<v-card-actions>
<v-btn
v-if="!item.added"
rounded
color="blue"
:disabled="disabled"
@click="listRepo(item)"
>
LIST REPO
</v-btn>
</v-card-actions>
</v-card>
<v-row justify="center" class="mt-2">
<v-btn
class="mx-2"
fab
dark
large
color="cyan"
:disabled="!pageInfo_.hasPreviousPage||disabled"
@click="getAllRepo(undefined,pageInfo_.startCursor)"
>
<v-icon>
fas fa-arrow-left
</v-icon>
</v-btn>
<v-btn
class="mx-2"
fab
dark
large
color="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>
<script lang="ts">
import { Component, Vue, Prop, Emit } from 'nuxt-property-decorator'
@Component
export default class MyStore extends Vue {
@Prop({ required: true }) readonly dialog!: boolean
@Prop({ required: true }) readonly allRepo!: Array<object>
@Prop({ required: true }) readonly pageInfo_!: object
@Prop({ required: true }) readonly disabled!: boolean
@Emit()
getAllRepo(after_: string,before_:string) {
return { after_,before_ }
}
@Emit()
listRepo(item:object) {
return { item}
}
}
</script>
이제 리디렉션 URL을 수락하려면 github login create
components/dashboard_components/DashboardRepoAll.vue
에서 얻은 토큰을 저장하고 다음 코드를 작성하기 위한 경로가 필요합니다.<template>
<v-row justify="center" align="center" :class="['text-h1']"
>REDIRECTING...</v-row
>
</template>
<script lang="ts">
import Cookies from 'js-cookie'
import { Component, Vue } from 'nuxt-property-decorator'
import axios from 'axios'
import {configs} from '@/utils/configs.js'
@Component
export default class MyStore extends Vue {
async mounted() {
if (this.$route.query.token) {
Cookies.set('token', this.$route.query.token)
if(Cookies.get('redirect')){
const redirect=Cookies.get('redirect');
window.location.href=`${redirect}`;
return
}
window.location.href = '/'
} else {
const token = Cookies.get('token')
const { data } = await axios.post(`${configs.save_paypal_url}`, {
token,
email: this.$route.query.email,
})
if (data.status) {
window.location.href = '/dashboard'
} else {
window.location.href = '/dashboard?error=save_paypal'
}
}
}
}
</script>
또한 판매하는 저장소를 공유할 수 있는 링크가 있어야 합니다
pages/callback.vue
.<template>
<v-row justify="center" align="center" :class="['text-h1']"
>
<v-card
class="mx-auto my-12"
max-width="1000"
>
<template slot="progress">
<v-progress-linear
color="deep-purple"
height="10"
indeterminate
></v-progress-linear>
</template>
<v-img
height="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-divider class="mx-4"></v-divider>
<v-card-title>$ {{item.amount}}</v-card-title>
<v-card-actions>
<v-btn
v-if="item.username !== username_"
color="deep-purple lighten-2"
text
:disabled="disabled"
@click="buyNow(item.repo_id,item.username,item.name)"
>
BUY NOW
</v-btn>
<v-btn
v-if="item.username === username_"
:disabled="disabled"
class="d-flex justify-end"
color="deep-purple lighten-2"
:href="item.url"
target="_blank"
text
>
GO TO URL
</v-btn>
</v-card-actions>
</v-card>
</v-row>
</template>
<script lang="ts">
import Cookies from 'js-cookie'
import { Component, Vue } from 'nuxt-property-decorator'
import {configs} from '@/utils/configs.js'
import axios from 'axios'
@Component
export default class MyStore extends Vue {
public disabled:boolean=false
public username_:string=""
public item:object={}
async mounted(){
Cookies.remove("redirect")
const username = this.$route.query.username
const name = this.$route.query.name
const url=configs.repo_detail_url
const {data}=await axios.post(`${url}`,{username,name})
this.item=data
if(Cookies.get("token")){
const token=Cookies.get("token")
const _url = configs.get_profile_url
const profile = await this.$axios.get(`${_url}?token=${token}`)
this.username_ = profile.data.data.login
}
}
async buyNow(id:any,username:string,name:string) {
this.disabled=true;
const token = Cookies.get('token')
if(!token){
window.location.href="/login"
Cookies.set('redirect', `/${username}/${name}`)
return
}
Cookies.remove("redirect")
const url=<string>configs.buy_paypal_url;
const res = await this.$axios.post(url, { id, token })
if (res.data) {
const link=res.data.result.links.filter((a:any)=>a.rel==="approve")[0].href
window.location.href=link;
}else{
this.disabled=false;
alert("error")
}
}
}
</script>
이제 프론트엔드 생성을 마쳤습니다. 2단계에서 백엔드를 생성해 보겠습니다.
Reference
이 문제에 관하여(1단계 - Nuxtjs를 사용하여 프런트엔드 만들기), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/spiritbro1/step-1-create-our-frontend-using-nuxtjs-1gkf텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)