mirror of
https://github.com/tornadocash/trusted-setup-server.git
synced 2024-11-22 01:46:52 +01:00
add table layout
-change route to make contribution
This commit is contained in:
parent
0de5c68d56
commit
213a7879fd
1
assets/img/icons/arrow-left.svg
Normal file
1
assets/img/icons/arrow-left.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="9" height="16"><path fill-rule="evenodd" d="M8.713 1.691L2.404 8l6.309 6.309a.992.992 0 1 1-1.404 1.404L.353 8.758C.332 8.74.306 8.733.287 8.713A.984.984 0 0 1-.002 8a.984.984 0 0 1 .289-.713c.019-.02.045-.027.066-.044L7.309.287a.992.992 0 1 1 1.404 1.404z"/></svg>
|
After Width: | Height: | Size: 312 B |
1
assets/img/icons/arrow-right.svg
Normal file
1
assets/img/icons/arrow-right.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="9" height="16"><path fill-rule="evenodd" d="M8.713 8.713c-.019.02-.045.027-.066.045l-6.956 6.955a.992.992 0 1 1-1.404-1.404L6.596 8 .287 1.691A.992.992 0 1 1 1.691.287l6.956 6.956c.021.017.047.024.066.044A.984.984 0 0 1 9.002 8a.984.984 0 0 1-.289.713z"/></svg>
|
After Width: | Height: | Size: 308 B |
1
assets/img/icons/emoticon-sad.svg
Normal file
1
assets/img/icons/emoticon-sad.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24"><path fill="#eee" d="M20,12A8,8 0 0,0 12,4A8,8 0 0,0 4,12A8,8 0 0,0 12,20A8,8 0 0,0 20,12M22,12A10,10 0 0,1 12,22A10,10 0 0,1 2,12A10,10 0 0,1 12,2A10,10 0 0,1 22,12M15.5,8C16.3,8 17,8.7 17,9.5C17,10.3 16.3,11 15.5,11C14.7,11 14,10.3 14,9.5C14,8.7 14.7,8 15.5,8M10,9.5C10,10.3 9.3,11 8.5,11C7.7,11 7,10.3 7,9.5C7,8.7 7.7,8 8.5,8C9.3,8 10,8.7 10,9.5M12,14C13.75,14 15.29,14.72 16.19,15.81L14.77,17.23C14.32,16.5 13.25,16 12,16C10.75,16 9.68,16.5 9.23,17.23L7.81,15.81C8.71,14.72 10.25,14 12,14Z" /></svg>
|
After Width: | Height: | Size: 629 B |
3
assets/img/icons/search.svg
Normal file
3
assets/img/icons/search.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16">
|
||||
<path fill="#94FEBF" fill-rule="evenodd" d="M15.678 15.678a1.045 1.045 0 0 1-1.478 0l-3.06-3.06A6.941 6.941 0 0 1 7 14a7 7 0 1 1 7-7 6.941 6.941 0 0 1-1.382 4.14l3.06 3.06c.408.408.408 1.07 0 1.478zM7 2a5 5 0 1 0 .001 10.001A5 5 0 0 0 7 2z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 318 B |
@ -78,6 +78,30 @@
|
||||
border-radius: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
&.is-icon {
|
||||
padding:0;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
|
||||
svg {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
path:not(.no-hover) {
|
||||
fill: #87feb7;
|
||||
transition: fill .15s ease-out;
|
||||
}
|
||||
}
|
||||
|
||||
&:focus:not(:active) {
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.box {
|
||||
@ -155,6 +179,34 @@
|
||||
.label {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
&.is-horizontal {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
@include mobile {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.field-label.is-normal {
|
||||
padding-top: 0;
|
||||
margin-right: 1.5rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.currently {
|
||||
font-size: .85rem;
|
||||
|
||||
span {
|
||||
color: $primary;
|
||||
font-size: 2.5rem;
|
||||
font-weight: $weight-bold;
|
||||
}
|
||||
|
||||
&:not(:last-child) {
|
||||
margin-bottom: $block-spacing;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -197,3 +249,249 @@
|
||||
to {
|
||||
transform: rotate(0deg); }
|
||||
}
|
||||
|
||||
.b-table {
|
||||
.table {
|
||||
a {
|
||||
color: $primary;
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
th {
|
||||
font-weight: $weight-normal;
|
||||
}
|
||||
|
||||
td {
|
||||
border-color: rgba($primary, .5)
|
||||
}
|
||||
|
||||
td, th {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
tbody {
|
||||
tr {
|
||||
&:last-child {
|
||||
td {
|
||||
border-bottom-width: 1px;
|
||||
}
|
||||
}
|
||||
|
||||
&:not(.is-selected) {
|
||||
&:nth-child(odd) {
|
||||
background-color: $table-striped-row-even-background-color;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: $table-row-hover-background-color;
|
||||
&:nth-child(odd) {
|
||||
background-color: $table-striped-row-even-hover-background-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&:not(.is-selected).is-empty {
|
||||
background-color: transparent;
|
||||
|
||||
&:hover {
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.dropdown.is-expanded {
|
||||
min-width: 75px;
|
||||
}
|
||||
}
|
||||
|
||||
.icon {
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: contain;
|
||||
|
||||
&-emoticon-sad {
|
||||
background-image: url('../img/icons/emoticon-sad.svg');
|
||||
}
|
||||
|
||||
&.icon-48px {
|
||||
height: 48px;
|
||||
width: 48px;
|
||||
}
|
||||
}
|
||||
|
||||
.table-search {
|
||||
.icon {
|
||||
mask-image: url("../img/icons/search.svg");
|
||||
mask-position: center;
|
||||
mask-repeat: no-repeat;
|
||||
mask-size: 16px 16px;
|
||||
|
||||
background-color: $input-placeholder-color;
|
||||
}
|
||||
|
||||
.input {
|
||||
&:hover {
|
||||
~ .icon {
|
||||
background-color: $input-hover-color;
|
||||
}
|
||||
}
|
||||
|
||||
&:focus {
|
||||
~ .icon {
|
||||
background-color: $primary;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.dropdown.is-mobile-modal.is-expanded {
|
||||
.dropdown-trigger {
|
||||
.control {
|
||||
.input {
|
||||
&::after {
|
||||
border: 1px solid #393939;
|
||||
border-radius: 1px;
|
||||
border-right: 0;
|
||||
border-top: 0;
|
||||
content: " ";
|
||||
display: block;
|
||||
margin-top: -0.5em;
|
||||
pointer-events: none;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
transform: rotate(-45deg);
|
||||
transform-origin: center;
|
||||
height: .625em;
|
||||
width: .625em;
|
||||
right: 1.125em;
|
||||
transition: border-color .15s ease-in-out;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
&::after {
|
||||
border-color: $white;
|
||||
}
|
||||
}
|
||||
|
||||
&:focus {
|
||||
&::after {
|
||||
border-color: $primary;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.is-loading {
|
||||
.input {
|
||||
&::after {
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
&::after {
|
||||
height: 1.14rem;
|
||||
width: 1.14rem;
|
||||
right: .86rem;
|
||||
top: .86rem;
|
||||
border-radius: 1.14rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.dropdown-menu {
|
||||
@include touch {
|
||||
max-width: 460px;
|
||||
}
|
||||
|
||||
> .dropdown-content {
|
||||
overflow: hidden;
|
||||
margin: 1px;
|
||||
|
||||
> .dropdown-item {
|
||||
font-size: 1rem;
|
||||
padding: 0.675rem 1.25rem;
|
||||
transition: color .15s ease-in-out, background-color .15s ease-in-out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.is-active {
|
||||
.dropdown-trigger {
|
||||
.control {
|
||||
.input {
|
||||
border-color: $primary;
|
||||
|
||||
&::after {
|
||||
border-color: $primary;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.is-top-right {
|
||||
.dropdown-menu {
|
||||
padding-top: 0px;
|
||||
padding-bottom: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.pagination {
|
||||
&-previous, &-next, &-link {
|
||||
background-color: rgba($primary, .104);
|
||||
font-weight: $weight-bold;
|
||||
|
||||
&:hover {
|
||||
background-color: $primary;
|
||||
}
|
||||
|
||||
&[disabled] {
|
||||
opacity: .5;
|
||||
|
||||
&:hover {
|
||||
background-color: rgba($primary, .104);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-previous, &-next {
|
||||
.icon {
|
||||
width: 9px;
|
||||
height: 16px;
|
||||
background-color: $primary
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.icon {
|
||||
background-color: $primary-invert;
|
||||
}
|
||||
}
|
||||
|
||||
&[disabled] {
|
||||
&:hover {
|
||||
.icon {
|
||||
background-color: $primary;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-previous {
|
||||
.icon {
|
||||
mask-image: url("../img/icons/arrow-left.svg");
|
||||
}
|
||||
}
|
||||
|
||||
&-next {
|
||||
.icon {
|
||||
mask-image: url("../img/icons/arrow-right.svg");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -129,6 +129,36 @@ $dropdown-background-color: $modal-background-background-color;
|
||||
$widescreen-enabled: false;
|
||||
$fullhd-enabled: false;
|
||||
|
||||
$table-background-color: transparent;
|
||||
$table-color: $white;
|
||||
$table-head-cell-color: $white;
|
||||
$table-head-cell-border-width: 0 0 4px;
|
||||
$table-cell-border: 1px solid $primary;
|
||||
$table-striped-row-even-background-color: rgba($primary, .104);
|
||||
$table-row-hover-background-color: rgba($primary, .154);
|
||||
$table-striped-row-even-hover-background-color: rgba($primary, .154);
|
||||
$table-cell-padding: 1.5em 0.75em;
|
||||
|
||||
$pagination-color: $primary;
|
||||
$pagination-border-color: $primary;
|
||||
|
||||
$pagination-hover-color: $primary-invert;
|
||||
$pagination-hover-border-color: $primary;
|
||||
|
||||
$pagination-focus-color: $pagination-hover-color;
|
||||
$pagination-focus-border-color: $pagination-hover-border-color;
|
||||
|
||||
$pagination-active-color: $pagination-hover-color;
|
||||
$pagination-active-border-color: $pagination-hover-border-color;
|
||||
|
||||
$pagination-disabled-color: $primary;
|
||||
$pagination-disabled-background-color: rgba($primary, .104);
|
||||
$pagination-disabled-border-color: $primary;
|
||||
|
||||
$pagination-current-color: $primary-invert;
|
||||
$pagination-current-background-color: $primary;
|
||||
$pagination-current-border-color: $primary;
|
||||
|
||||
.columns {
|
||||
@include from(576px) {
|
||||
&.is-small {
|
||||
|
9
components/icons/Link.vue
Normal file
9
components/icons/Link.vue
Normal file
@ -0,0 +1,9 @@
|
||||
<template>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18">
|
||||
<path
|
||||
fill="#94FEBF"
|
||||
fill-rule="evenodd"
|
||||
d="M17 18H1a1 1 0 0 1-1-1v-4a1 1 0 0 1 2 0v3h14v-3a1 1 0 0 1 2 0v4a1 1 0 0 1-1 1zm-7.134-6.332a1.08 1.08 0 0 1-.78.315C9.056 11.985 9.03 12 9 12c-.03 0-.056-.015-.086-.017a1.08 1.08 0 0 1-.78-.315L4.298 7.833a1.086 1.086 0 0 1 1.534-1.535L8 8.466V1a1 1 0 0 1 2 0v7.466l2.167-2.168a1.087 1.087 0 0 1 1.535 0 1.087 1.087 0 0 1 0 1.535l-3.836 3.835z"
|
||||
/>
|
||||
</svg>
|
||||
</template>
|
280
pages/index.vue
280
pages/index.vue
@ -1,159 +1,167 @@
|
||||
<template>
|
||||
<div class="ceremony">
|
||||
<div class="title is-size-1 is-spaced">
|
||||
Hello, <span>@{{ user.handle }}</span>
|
||||
</div>
|
||||
<div class="subtitle">Lorem ipsum dolor sit amet, consectetur?</div>
|
||||
<p class="p">
|
||||
If you don’t trust binaries, we encorage you to follow this <a href="">instruction</a> to
|
||||
contribute by compiling from source code. It is very easy!
|
||||
<h1 class="title is-size-1 is-spaced">Lorem <span>Ipsum Dolor</span></h1>
|
||||
<p class="p is-size-5">
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut
|
||||
labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco
|
||||
laboris nisi ut aliquip ex ea commodo consequat.
|
||||
</p>
|
||||
|
||||
<div class="columns is-centered">
|
||||
<div class="column is-one-third">
|
||||
<div class="box">
|
||||
<div class="title is-5">Lorem ipsum</div>
|
||||
<Cloak />
|
||||
</div>
|
||||
</div>
|
||||
<div class="column is-one-third">
|
||||
<div :class="{ 'is-hovered': isLoggedIn }" class="box">
|
||||
<div class="title is-5">Lorem ipsum</div>
|
||||
<div v-if="isLoggedIn" class="fields">
|
||||
<b-field label="Name">
|
||||
<b-input v-model="user.name"></b-input>
|
||||
</b-field>
|
||||
<b-field label="Company">
|
||||
<b-input v-model="user.company"></b-input>
|
||||
</b-field>
|
||||
</div>
|
||||
<div v-else class="buttons">
|
||||
<b-button @click="logIn" type="is-primary" outlined expanded>
|
||||
Sign In
|
||||
</b-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-show="status.msg !== ''" class="status">
|
||||
<div :class="status.type" class="status-message">{{ status.msg }}</div>
|
||||
<div v-show="status.type === ''" class="status-spinner"></div>
|
||||
</div>
|
||||
|
||||
<div class="buttons is-centered">
|
||||
<b-button
|
||||
v-if="!isContributeBtnDisabled"
|
||||
@click="makeContribution"
|
||||
type="is-primary"
|
||||
outlined
|
||||
>
|
||||
<b-button type="is-primary" outlined tag="router-link" to="/make-contribution">
|
||||
Make the contribution
|
||||
</b-button>
|
||||
<b-button
|
||||
v-if="isContributeBtnDisabled && status.type === 'is-success'"
|
||||
type="is-primary"
|
||||
tag="a"
|
||||
href="https://twitter.com/intent/tweet?text=Hello%20world"
|
||||
target="_blank"
|
||||
outlined
|
||||
>
|
||||
Tweet about your contribution
|
||||
</b-button>
|
||||
</div>
|
||||
<div class="currently">Currently there are <span>8999</span> contributions</div>
|
||||
|
||||
<b-table
|
||||
:data="filteredContributions"
|
||||
:hoverable="true"
|
||||
:mobile-cards="false"
|
||||
:per-page="rowsPerPage"
|
||||
paginated
|
||||
pagination-position="both"
|
||||
>
|
||||
<template slot-scope="props">
|
||||
<b-table-column field="id" label="#" width="40" numeric>
|
||||
{{ props.row.id }}
|
||||
</b-table-column>
|
||||
|
||||
<b-table-column label="Account">
|
||||
<a :href="`#${props.row.account}`" target="_blank">{{ props.row.account }}</a>
|
||||
</b-table-column>
|
||||
|
||||
<b-table-column field="name" label="Name">
|
||||
{{ props.row.name }}
|
||||
</b-table-column>
|
||||
|
||||
<b-table-column field="company" label="Company">
|
||||
{{ props.row.company }}
|
||||
</b-table-column>
|
||||
|
||||
<b-table-column label="Attestation">
|
||||
<a :href="props.row.attestation" target="_blank">{{ props.row.account }}</a>
|
||||
</b-table-column>
|
||||
|
||||
<b-table-column>
|
||||
<a :href="props.row.contribution" class="button is-icon">
|
||||
<Link />
|
||||
</a>
|
||||
</b-table-column>
|
||||
</template>
|
||||
|
||||
<template slot="empty">
|
||||
<section class="section">
|
||||
<div class="content has-text-centered">
|
||||
<p>
|
||||
<span class="icon icon-emoticon-sad icon-48px"></span>
|
||||
</p>
|
||||
<p>Nothing here.</p>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<template slot="top-left">
|
||||
<b-field class="table-search">
|
||||
<b-input
|
||||
v-model="contributionSearch"
|
||||
placeholder="Search..."
|
||||
type="search"
|
||||
icon="magnify"
|
||||
></b-input>
|
||||
</b-field>
|
||||
</template>
|
||||
|
||||
<template slot="bottom-left">
|
||||
<b-field horizontal label="Show">
|
||||
<b-dropdown v-model="rowsPerPage" expanded aria-role="list" position="is-top-right">
|
||||
<div slot="trigger" class="control">
|
||||
<div class="input">
|
||||
<span>{{ rowsPerPage }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<b-dropdown-item
|
||||
v-for="(rows, index) in [10, 15, 20, 50]"
|
||||
:key="index"
|
||||
:value="rows"
|
||||
aria-role="listitem"
|
||||
>
|
||||
{{ rows }}
|
||||
</b-dropdown-item>
|
||||
</b-dropdown>
|
||||
</b-field>
|
||||
</template>
|
||||
</b-table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/* eslint-disable no-console */
|
||||
import Cloak from '@/components/Cloak'
|
||||
const timeout = (ms) => new Promise((resolve) => setTimeout(resolve, ms))
|
||||
import Link from '@/components/icons/Link'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Cloak
|
||||
Link
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isContributeBtnDisabled: false,
|
||||
status: {
|
||||
type: '',
|
||||
msg: ''
|
||||
},
|
||||
user: { name: '', handle: 'Anonymous', company: '' }
|
||||
contributions: [
|
||||
{
|
||||
id: 1,
|
||||
account: '@VitalikButerin',
|
||||
name: 'Vitalik Buterin',
|
||||
company: 'Ethereum',
|
||||
attestation: 'https://twitter.com/VitalikButerin/status/1220158987456237568',
|
||||
contribution: '#'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
account: '@Chims1974',
|
||||
name: 'Rickey Kline',
|
||||
company: 'Big Wheel',
|
||||
attestation: '#',
|
||||
contribution: '#'
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
account: '@Diguest',
|
||||
name: 'Ryan Obrien',
|
||||
company: 'Brilliant Home',
|
||||
attestation: '#',
|
||||
contribution: '#'
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
account: '@Mathervenrat',
|
||||
name: 'William Hartwig',
|
||||
company: 'New World',
|
||||
attestation: '#',
|
||||
contribution: '#'
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
account: '@Hichercy',
|
||||
name: 'Wayne Biggins',
|
||||
company: 'Balanced Fortune',
|
||||
attestation: '#',
|
||||
contribution: '#'
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
account: '',
|
||||
name: 'Anonymous',
|
||||
company: '',
|
||||
attestation: '',
|
||||
contribution: '#'
|
||||
}
|
||||
],
|
||||
rowsPerPage: 10,
|
||||
contributionSearch: ''
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
isLoggedIn() {
|
||||
return !!this.user.name && this.user.name !== 'Anonymous'
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
try {
|
||||
const data = await this.$axios.$get('/api/user_data')
|
||||
console.log('data', data)
|
||||
if (data.name !== 'Anonymous') {
|
||||
this.user.handle = data.handle
|
||||
this.user.name = data.name
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('user_data fail', e)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async makeContribution({ retry = 0 } = {}) {
|
||||
try {
|
||||
this.isContributeBtnDisabled = true
|
||||
|
||||
this.status.msg = 'Downloading last contribution'
|
||||
this.status.type = ''
|
||||
let data = await fetch('api/challenge')
|
||||
data = new Uint8Array(await data.arrayBuffer())
|
||||
|
||||
this.status.msg = 'Generating random contribution'
|
||||
await timeout(100) // allow UI to update before freezing in wasm
|
||||
console.log('Source params', data)
|
||||
const contribute = await this.$contribute()
|
||||
const result = contribute(data)
|
||||
console.log('Updated params', result)
|
||||
|
||||
this.status.msg = 'Uploading and verifying your contribution'
|
||||
console.log('this.user.name', this.user)
|
||||
const formData = new FormData()
|
||||
formData.append('response', new Blob([result], { type: 'application/octet-stream' }))
|
||||
formData.append('name', this.user.name)
|
||||
formData.append('company', this.user.company)
|
||||
const resp = await fetch('api/response', {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
})
|
||||
|
||||
if (resp.ok) {
|
||||
this.status.msg = 'Your contribution is verified and recorded. THX BYE.'
|
||||
this.status.type = 'is-success'
|
||||
} else if (resp.status === 422) {
|
||||
if (retry < 3) {
|
||||
console.log(`Looks like someone else uploaded contribution ahead of us, retrying`)
|
||||
await this.makeContribution({ retry: retry++ })
|
||||
} else {
|
||||
this.status.msg = `Failed to upload your contribution after ${retry} attempts`
|
||||
this.status.type = 'is-danger'
|
||||
this.isContributeBtnDisabled = false
|
||||
}
|
||||
} else {
|
||||
this.status.msg = 'Error uploading your contribution'
|
||||
this.status.type = 'is-danger'
|
||||
this.isContributeBtnDisabled = false
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e.message)
|
||||
this.status.msg = e.message
|
||||
this.status.type = 'is-danger'
|
||||
this.isContributeBtnDisabled = false
|
||||
}
|
||||
},
|
||||
logIn() {
|
||||
window.location.replace('/api/connect')
|
||||
filteredContributions() {
|
||||
return this.contributions.filter((contribution) => {
|
||||
return contribution.name.toLowerCase().includes(this.contributionSearch.toLowerCase())
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
160
pages/make-contribution.vue
Normal file
160
pages/make-contribution.vue
Normal file
@ -0,0 +1,160 @@
|
||||
<template>
|
||||
<div class="ceremony">
|
||||
<h1 class="title is-size-1 is-spaced">
|
||||
Hello, <span>@{{ user.handle }}</span>
|
||||
</h1>
|
||||
<h2 class="subtitle">Lorem ipsum dolor sit amet, consectetur?</h2>
|
||||
<p class="p">
|
||||
If you don’t trust binaries, we encorage you to follow this <a href="">instruction</a> to
|
||||
contribute by compiling from source code. It is very easy!
|
||||
</p>
|
||||
|
||||
<div class="columns is-centered">
|
||||
<div class="column is-one-third">
|
||||
<div class="box">
|
||||
<div class="title is-5">Lorem ipsum</div>
|
||||
<Cloak />
|
||||
</div>
|
||||
</div>
|
||||
<div class="column is-one-third">
|
||||
<div :class="{ 'is-hovered': isLoggedIn }" class="box">
|
||||
<div class="title is-5">Lorem ipsum</div>
|
||||
<div v-if="isLoggedIn" class="fields">
|
||||
<b-field label="Name">
|
||||
<b-input v-model="user.name"></b-input>
|
||||
</b-field>
|
||||
<b-field label="Company">
|
||||
<b-input v-model="user.company"></b-input>
|
||||
</b-field>
|
||||
</div>
|
||||
<div v-else class="buttons">
|
||||
<b-button @click="logIn" type="is-primary" outlined expanded>
|
||||
Sign In
|
||||
</b-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-show="status.msg !== ''" class="status">
|
||||
<div :class="status.type" class="status-message">{{ status.msg }}</div>
|
||||
<div v-show="status.type === ''" class="status-spinner"></div>
|
||||
</div>
|
||||
|
||||
<div class="buttons is-centered">
|
||||
<b-button
|
||||
v-if="!isContributeBtnDisabled"
|
||||
@click="makeContribution"
|
||||
type="is-primary"
|
||||
outlined
|
||||
>
|
||||
Make the contribution
|
||||
</b-button>
|
||||
<b-button
|
||||
v-if="isContributeBtnDisabled && status.type === 'is-success'"
|
||||
type="is-primary"
|
||||
tag="a"
|
||||
href="https://twitter.com/intent/tweet?text=Hello%20world"
|
||||
target="_blank"
|
||||
outlined
|
||||
>
|
||||
Tweet about your contribution
|
||||
</b-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/* eslint-disable no-console */
|
||||
import Cloak from '@/components/Cloak'
|
||||
const timeout = (ms) => new Promise((resolve) => setTimeout(resolve, ms))
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Cloak
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isContributeBtnDisabled: false,
|
||||
status: {
|
||||
type: '',
|
||||
msg: ''
|
||||
},
|
||||
user: { name: '', handle: 'Anonymous', company: '' }
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
isLoggedIn() {
|
||||
return !!this.user.name && this.user.name !== 'Anonymous'
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
try {
|
||||
const data = await this.$axios.$get('/api/user_data')
|
||||
console.log('data', data)
|
||||
if (data.name !== 'Anonymous') {
|
||||
this.user.handle = data.handle
|
||||
this.user.name = data.name
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('user_data fail', e)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async makeContribution({ retry = 0 } = {}) {
|
||||
try {
|
||||
this.isContributeBtnDisabled = true
|
||||
|
||||
this.status.msg = 'Downloading last contribution'
|
||||
this.status.type = ''
|
||||
let data = await fetch('api/challenge')
|
||||
data = new Uint8Array(await data.arrayBuffer())
|
||||
|
||||
this.status.msg = 'Generating random contribution'
|
||||
await timeout(100) // allow UI to update before freezing in wasm
|
||||
console.log('Source params', data)
|
||||
const contribute = await this.$contribute()
|
||||
const result = contribute(data)
|
||||
console.log('Updated params', result)
|
||||
|
||||
this.status.msg = 'Uploading and verifying your contribution'
|
||||
console.log('this.user.name', this.user)
|
||||
const formData = new FormData()
|
||||
formData.append('response', new Blob([result], { type: 'application/octet-stream' }))
|
||||
formData.append('name', this.user.name)
|
||||
formData.append('company', this.user.company)
|
||||
const resp = await fetch('api/response', {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
})
|
||||
|
||||
if (resp.ok) {
|
||||
this.status.msg = 'Your contribution is verified and recorded. THX BYE.'
|
||||
this.status.type = 'is-success'
|
||||
} else if (resp.status === 422) {
|
||||
if (retry < 3) {
|
||||
console.log(`Looks like someone else uploaded contribution ahead of us, retrying`)
|
||||
await this.makeContribution({ retry: retry++ })
|
||||
} else {
|
||||
this.status.msg = `Failed to upload your contribution after ${retry} attempts`
|
||||
this.status.type = 'is-danger'
|
||||
this.isContributeBtnDisabled = false
|
||||
}
|
||||
} else {
|
||||
this.status.msg = 'Error uploading your contribution'
|
||||
this.status.type = 'is-danger'
|
||||
this.isContributeBtnDisabled = false
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e.message)
|
||||
this.status.msg = e.message
|
||||
this.status.type = 'is-danger'
|
||||
this.isContributeBtnDisabled = false
|
||||
}
|
||||
},
|
||||
logIn() {
|
||||
window.location.replace('/api/connect')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
Loading…
Reference in New Issue
Block a user