Compare commits

..
Author SHA1 Message Date
basti 1399746124 Build production from 1ea5305 2019-05-29 10:12:22 +02:00
basti 0a9a80065f Build production from 18be60d 2019-05-10 16:03:27 +02:00
basti 266bdd8687 Build production from 4c2d95f 2019-05-08 14:58:33 +02:00
basti de44ec73f7 Build production from 6593005 2019-05-01 20:32:19 +01:00
basti e60cc3a127 Build production from 24a3d8b 2019-04-26 19:01:24 +01:00
basti 90c0b19f00 Build production from d02fb47 2019-04-25 20:55:13 +01:00
bumi 69586a809d Build production from 0283913 2019-04-24 17:09:13 +02:00
bumi fd4b970f41 Build production from 83fd9a9 2019-04-19 15:50:05 +02:00
bumi b76ece5c49 Build production from 6dcbd1e 2019-04-18 11:26:28 +02:00
bumi 9106137ee5 Build production from a2ddb23 2019-04-17 22:48:38 +02:00
basti 8edfef5fae Build production from 64997d7 2018-07-20 12:33:33 +02:00
basti 995bc80f14 Build production from 297ed4e 2018-07-19 09:29:05 +02:00
basti 857f577df1 Build production from ef0f3ff 2018-07-12 11:31:49 +02:00
basti bdf457e20c Build production from c074ccf 2018-06-17 16:16:38 +02:00
basti 77ea34e7ec Build production from 575c1a1 2018-06-14 19:25:49 +02:00
basti 7c4abc57f1 Build production from e78832e 2018-06-14 15:32:16 +02:00
basti 2c1e97acff Build production from a0ee2f7 2018-06-07 13:37:32 +02:00
basti 29bbf6fe96 Build production from d070288 2018-06-04 14:15:25 +02:00
basti 5eca562744 Build production from 3e7fe1b 2018-04-21 20:21:11 +02:00
basti d7b505aeb3 Build production from b1db64a 2017-06-15 11:24:29 -07:00
basti 6233ffe550 Build production from 9b37f13 2017-06-13 14:39:19 +02:00
basti c229832734 Build production from 8aa86fa 2017-06-09 00:53:43 +02:00
basti 52ff03592c Build production from 40d6b99 2017-05-31 17:07:49 +02:00
basti cd74429dd7 Build production from 2288250 2017-05-31 16:55:24 +02:00
basti 88bb2b9311 Build production from dda5a8d 2017-05-14 19:58:28 +02:00
basti 2cb3fbeb85 Build production from 0b7afc0 2017-05-14 01:11:22 +02:00
basti 7a0d3a0e73 Build production from b8ded8e 2017-02-18 18:06:19 +08:00
basti d1a55a5171 Build production from 7c98de3 2017-02-08 14:34:49 +08:00
basti c848f204b9 Build production from 3eb5845 2017-02-07 22:39:51 +08:00
basti e76e383854 Build production from 9cc4f85 2017-02-07 21:58:15 +08:00
basti 2817b4c389 Build production from b15191a 2017-02-07 21:18:42 +08:00
basti e119f4a29e Add gitignore config 2017-02-07 21:06:24 +08:00
267 changed files with 115733 additions and 37552 deletions

No files matched your search

-20
View File
@@ -1,20 +0,0 @@
# EditorConfig helps developers define and maintain consistent
# coding styles between different editors and IDEs
# editorconfig.org
root = true
[*]
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
indent_style = space
indent_size = 2
[*.hbs]
insert_final_newline = false
[*.{diff,md}]
trim_trailing_whitespace = false
-9
View File
@@ -1,9 +0,0 @@
{
/**
Ember CLI sends analytics information by default. The data is completely
anonymous, but there are times when you might want to disable this behavior.
Setting `disableAnalytics` to true will prevent any data from being sent.
*/
"disableAnalytics": true
}
-21
View File
@@ -1,21 +0,0 @@
# unconventional js
/blueprints/*/files/
/vendor/
# compiled output
/dist/
/tmp/
/release/
# dependencies
/bower_components/
/node_modules/
# misc
/coverage/
!.*
# ember-try
/.node_modules.ember-try/
/bower.json.ember-try
/package.json.ember-try
-55
View File
@@ -1,55 +0,0 @@
module.exports = {
root: true,
parserOptions: {
ecmaVersion: 2018,
sourceType: 'module'
},
globals: {
console: true
},
plugins: [
'ember'
],
extends: [
'eslint:recommended',
'plugin:ember/recommended'
],
env: {
browser: true
},
rules: {
'ember/avoid-leaking-state-in-ember-objects': 'warn',
'no-console': 'off'
},
overrides: [
// node files
{
files: [
'.eslintrc.js',
'.template-lintrc.js',
'ember-cli-build.js',
'testem.js',
'blueprints/*/index.js',
'config/**/*.js',
'lib/*/index.js',
'server/**/*.js'
],
parserOptions: {
sourceType: 'script',
ecmaVersion: 2015
},
env: {
browser: false,
node: true
},
plugins: ['node'],
rules: Object.assign({}, require('eslint-plugin-node').configs.recommended.rules, {
// add your custom rules and overrides for node files here
// this can be removed once the following is fixed
// https://github.com/mysticatea/eslint-plugin-node/issues/77
'node/no-unpublished-require': 'off'
})
}
]
};
-4
View File
@@ -1,4 +0,0 @@
template: |
## Changes
$CHANGES
+9 -16
View File
@@ -1,26 +1,19 @@
# See https://help.github.com/ignore-files/ for more about ignoring files.
# compiled output
/dist/
/tmp/
/dist
/tmp
# dependencies
/bower_components/
/node_modules/
/node_modules
/bower_components
/scripts
# misc
/.env*
/.pnp*
/.sass-cache
/connect.lock
/coverage/
/coverage/*
/libpeerconnection.log
/npm-debug.log*
/testem.log
/yarn-error.log
.tm_properties
# ember-try
/.node_modules.ember-try/
/bower.json.ember-try
/package.json.ember-try
npm-debug.log*
testem.log
+1
View File
@@ -0,0 +1 @@
8.11.3
-10
View File
@@ -1,10 +0,0 @@
'use strict';
module.exports = {
extends: 'recommended',
rules: {
'simple-unless': false,
'no-nested-interactive': false
}
};
-29
View File
@@ -1,29 +0,0 @@
---
language: node_js
node_js:
- "10"
sudo: false
dist: xenial
notifications:
email:
on_success: never
on_failure: always
addons:
chrome: stable
cache:
directories:
- $HOME/.npm
env:
global:
# See https://git.io/vdao3 for details.
- JOBS=1
script:
- npm run lint:hbs
- npm run lint:js
- npm test
-3
View File
@@ -1,3 +0,0 @@
{
"ignore_dirs": ["tmp", "dist"]
}
-123
View File
@@ -1,123 +0,0 @@
[![Build Status](https://travis-ci.org/67P/kredits-web.svg?branch=master)](https://travis-ci.org/67P/kredits-web)
# kredits-web
This README outlines the details of collaborating on this Ember application.
A short introduction of this app could easily go here.
## Prerequisites
You will need the following things properly installed on your computer.
* [Git](https://git-scm.com/)
* [Node.js](https://nodejs.org/) (with npm)
* [Ember CLI](https://ember-cli.com/)
* [Google Chrome](https://google.com/chrome/)
## Installation
* `git clone git@github.com:67P/kredits-web.git` this repository
* `cd kredits-web`
* `npm install`
## Running / Development
* `ember serve` - by default kredits-web connects to the Ethreum Kovan network
* Visit your app at [http://localhost:4200](http://localhost:4200).
* Visit your tests at [http://localhost:4200/tests](http://localhost:4200/tests).
See [working with locally deployed contracts](https://github.com/67P/kredits-web#working-with-locally-deployed-contracts) for details on how to develop with locally deployed contracts.
### Code Generators
Make use of the many generators for code, try `ember help generate` for more details
### Running Tests
* `ember test`
* `ember test --server`
### Linting
* `npm run lint:hbs`
* `npm run lint:js`
* `npm run lint:js -- --fix`
### Building
* `ember build` (development)
* `ember build --environment production` (production)
### Deploying
_(You need collaborator permissions on the 5apps Deploy project.)_
`npm run deploy`
## Working with locally deployed contracts
The smart contracts and their JavaScript wrapper library are developed in the
[kredits-contracts](https://github.com/67P/kredits-contracts) repo/package.
You can run `kredits-web` on your machine, against a local, simulated Ethereum
network, provided e.g. by [ganache](http://truffleframework.com/ganache/).
[kredits-contracts](https://github.com/67P/kredits-contracts) holds all the tools
to start and set up such a simulated network, as well as to deploy smart
contracts to it.
These are the basic steps to get up and running:
#### 1. IPFS
Run a local IPFS deamon.
* Make sure CORS headers are configured. See [IPFS](#ipfs) for more info.
* `ipfs daemon`
#### 2. kredits-contracts
Get your local Ethereum development node running. (See [kredits-contracts README](https://github.com/67P/kredits-contracts)
for details.
* Clone [kredits-contracts](https://github.com/67P/kredits-contracts)
* `npm install`
* `npm run devchain` - runs a local development chain
* `npm run bootstrap` - bootstrap runs deploys all the contracts
* `npm link` - make the `kredits-contracts` module linkable as `kredits-contracts` on your machine (currently broken :( )
#### 3. kredits-web
With IPFS and Ethereum/ganache running, you can now start this Ember app.
* `npm link kredits-contracts` - link the local `kredits-contracts` package
* `npm run start:local` - WEB3_PROVIDER_URL=http://localhost:7545 must be set for local settings
If you restart the devchain your network ID changes. So kredits-contracts does not find the correct DAO address.
If that is the case the DAO address must be provided as `KREDITS_DAO_ADDRESS` environment variable.
* `npm run dao:address` in the kredits-contracts repo to find your address
* `KREDITS_DAO_ADDRESS=<0xYOURADDRESS> npm run start:local`
#### 4. Metamask network
Switch the network in Metamask to "Custom RPC" with the RPC URL `http://localhost:7545`.
#### IPFS
Install IPFS with your favorite package manager and run
ipfs init (on initial installation)
ipfs config --json API.HTTPHeaders.Access-Control-Allow-Origin '["localhost:4200"]'
ipfs config --json API.HTTPHeaders.Access-Control-Allow-Methods '["PUT", "GET", "POST"]'
ipfs config --json API.HTTPHeaders.Access-Control-Allow-Credentials '["true"]'
ipfs config Addresses.Gateway /ip4/127.0.0.1/tcp/8080
## Further Reading / Useful Links
* [ember.js](https://emberjs.com/)
* [ember-cli](https://ember-cli.com/)
* Development Browser Extensions
* [ember inspector for chrome](https://chrome.google.com/webstore/detail/ember-inspector/bmdblncegkenkacieihfhpjfppoconhi)
* [ember inspector for firefox](https://addons.mozilla.org/en-US/firefox/addon/ember-inspector/)
+1
View File
@@ -0,0 +1 @@
1.0.0
-14
View File
@@ -1,14 +0,0 @@
import Application from '@ember/application';
import Resolver from './resolver';
import loadInitializers from 'ember-load-initializers';
import config from './config/environment';
const App = Application.extend({
modulePrefix: config.modulePrefix,
podModulePrefix: config.podModulePrefix,
Resolver
});
loadInitializers(App, config.modulePrefix);
export default App;
@@ -1,78 +0,0 @@
import Component from '@ember/component';
import { computed } from '@ember/object';
import { and, notEmpty } from '@ember/object/computed';
import { isEmpty } from '@ember/utils';
import moment from 'moment';
export default Component.extend({
attributes: null,
contributors: Object.freeze([]),
isValidContributor: notEmpty('contributorId'),
isValidKind: notEmpty('kind'),
isValidAmount: computed('amount', function() {
return parseInt(this.amount, 10) > 0;
}),
isValidDescription: notEmpty('description'),
isValidUrl: notEmpty('url'),
isValid: and('isValidContributor',
'isValidKind',
'isValidAmount',
'isValidDescription'),
init () {
this._super(...arguments);
this.set('defaultDate', moment().startOf('hour').toDate());
// Default attributes used by reset
if (isEmpty(this.attributes)) {
this.set('attributes', {
contributorId: null,
kind: null,
date: this.defaultDate,
amount: null,
description: null,
url: null,
details: null
});
}
this.reset();
},
reset () {
this.setProperties(this.attributes);
},
actions: {
submit () {
if (!this.isValid) {
alert('Invalid data. Please review and try again.');
return;
}
const attributes = this.getProperties(Object.keys(this.attributes));
let dateInput = (attributes.date instanceof Array) ?
attributes.date[0] : attributes.date;
const [ date, time ] = dateInput.toISOString().split('T');
[ attributes.date, attributes.time ] = [ date, time ];
this.set('inProgress', true);
this.save(attributes)
.then((/*contribution*/) => {
this.reset();
}, err => {
console.warn(err);
window.alert('Something went wrong. Check the browser console for details.');
})
.finally(() => this.set('inProgress', false));
}
}
});
@@ -1,83 +0,0 @@
<form {{action "submit" on="submit"}}>
<label>
<p class="label">Contributor:</p>
<p>
<select required onchange={{action (mut contributorId) value="target.value"}}>
<option value="" selected disabled hidden></option>
{{#each contributors as |contributor|}}
<option value={{contributor.id}} selected={{eq contributorId contributor.id}}>{{contributor.name}}</option>
{{/each}}
</select>
</p>
</label>
<label>
<p class="label">Kind:</p>
<p>
<select required onchange={{action (mut kind) value="target.value"}}>
<option value="" selected disabled hidden></option>
<option value="community" selected={{eq kind "community"}}>Community</option>
<option value="design" selected={{eq kind "design"}}>Design</option>
<option value="dev" selected={{eq kind "dev"}}>Development</option>
<option value="docs" selected={{eq kind "docs"}}>Documentation</option>
<option value="ops" selected={{eq kind "ops"}}>IT Operations</option>
<option value="special" selected={{eq kind "special"}}>Special</option>
</select>
</p>
</label>
<label>
<p class="label">Date:</p>
<p>
{{ember-flatpickr
date=date
defaultDate=defaultDate
maxDate=defaultDate
enableTime=true
time_24hr=true
onChange=(action (mut date))
}}
</p>
</label>
<label>
<p class="label">Amount:</p>
<p>
{{input type="text"
placeholder="500"
value=amount
class=(if isValidAmount "valid" "")}}
</p>
</label>
<label>
<p class="label">Description:</p>
<p>
{{input type="text"
value=description
class=(if isValidDescription "valid" "")}}
</p>
</label>
<label>
<p class="label">URL (optional):</p>
<p>
{{input type="text"
value=url
class=(if isValidUrl "valid" "")}}
</p>
</label>
{{#if details}}
<label>
<p class="label">Details:</p>
<p>
<pre>
{{details}}
</pre>
</p>
</label>
{{/if}}
<p class="actions">
{{input type="submit"
disabled=inProgress
value=(if inProgress "Processing" "Save")}}
</p>
</form>
@@ -1,87 +0,0 @@
import Component from '@ember/component';
import { computed } from '@ember/object';
import { and, notEmpty } from '@ember/object/computed';
import { inject as service } from '@ember/service';
import { isPresent } from '@ember/utils';
import { isAddress } from 'web3-utils';
export default Component.extend({
kredits: service(),
router: service(),
attributes: null,
isValidAccount: computed('account', function() {
return isAddress(this.account);
}),
isValidName: notEmpty('name'),
isValidURL: notEmpty('url'),
isValidGithubUID: notEmpty('github_uid'),
isValidGithubUsername: notEmpty('github_username'),
isValidGiteaUsername: notEmpty('gitea_username'),
isValidWikiUsername: notEmpty('wiki_username'),
isValidZoomDisplayName: notEmpty('zoom_display_name'),
isValid: and(
'isValidAccount',
'isValidName',
'isValidGithubUID'
),
inProgress: false,
init () {
this._super(...arguments);
this.setDefaultAttributes();
this.reset();
},
setDefaultAttributes () {
if (isPresent(this.attributes)) { return; }
this.set('attributes', {
account: null,
name: null,
kind: 'person',
url: null,
github_username: null,
github_uid: null,
gitea_username: null,
wiki_username: null,
zoom_display_name: null
});
},
reset: function() {
this.setProperties(this.attributes);
},
actions: {
submit () {
if (!this.isValid) {
alert('Invalid data. Please review and try again.');
return;
}
const attributes = Object.keys(this.attributes);
const contributor = this.getProperties(attributes);
this.set('inProgress', true);
this.save(contributor).then(() => {
this.reset();
}).catch(err => {
console.warn(err);
window.alert('Something went wrong. Please check the browser console.');
}).finally(() => {
this.set('inProgress', false);
this.router.transitionTo('dashboard');
});
}
}
});
@@ -1,55 +0,0 @@
<form {{action "submit" on="submit"}}>
<p>
<label for="c-account">Ethereum account</label>
{{input name="account" id="c-account"
type="text" value=account
placeholder="0xF18E631Ea191aE4ebE70046Fcb01a436554421BA4"
class=(if isValidAccount "valid" "")}}
</p>
<p>
<label for="c-kind">Kind</label>
<select required onchange={{action (mut kind) value="target.value"}} id="c-kind">
<option value="person" selected={{eq kind "person"}}>Person</option>
<option value="organization" selected={{eq kind "organization"}}>Organization</option>
</select>
</p>
<p>
<label for="c-name">Name</label>
{{input name="name" type="text" value=name placeholder="Zero Cool"
class=(if isValidName "valid" "") id="c-name"}}
</p>
<p>
<label for="c-url">URL</label>
{{input name="url" type="text" value=url placeholder="http://zerocool.bit"
class=(if isValidURL "valid" "") id="c-url"}}
</p>
<p>
<label for="c-github-uid">GitHub UID</label>
{{input name="github_uid" type="text" value=github_uid placeholder="2342"
class=(if isValidGithubUID "valid" "") id="c-github-uid"}}
</p>
<p>
<label for="c-github-username">GitHub username</label>
{{input name="github_username" type="text" value=github_username placeholder="zerocool"
class=(if isValidGithubUsername "valid" "") id="c-github-username"}}
</p>
<p>
<label for="c-gitea-username">Gitea username</label>
{{input name="gitea_username" type="text" value=gitea_username placeholder="zerocool"
class=(if isValidGiteaUsername "valid" "") id="c-gitea-username"}}
</p>
<p>
<label for="c-wiki-username">Wiki username</label>
{{input name="wiki_username" type="text" value=wiki_username placeholder="ZeroCool"
class=(if isValidWikiUsername "valid" "") id="c-wiki-username"}}
</p>
<p>
<label for="c-zoom-display-name">Zoom display name</label>
{{input name="zoom_display_name" type="text" value=zoom_display_name placeholder="Zero Cool"
class=(if isValidZoomDisplayName "valid" "") id="c-zoom-display-name"}}
</p>
<p class="actions">
{{input type="submit" disabled=inProgress
value=(if inProgress "Processing" "Save")}}
</p>
</form>
-64
View File
@@ -1,64 +0,0 @@
import Component from '@ember/component';
import { computed } from '@ember/object';
import { and, notEmpty } from '@ember/object/computed';
export default Component.extend({
attributes: null,
contributors: Object.freeze([]),
isValidContributor: notEmpty('contributorId'),
isValidAmount: computed('amount', function() {
return parseInt(this.amount, 10) > 0;
}),
isValidDescription: notEmpty('description'),
isValidUrl: notEmpty('url'),
isValid: and('isValidContributor',
'isValidAmount',
'isValidDescription'),
init () {
this._super(...arguments);
// Default attributes used by reset
this.set('attributes', {
contributorId: null,
kind: 'community',
amount: null,
description: null,
url: null,
});
},
didInsertElement() {
this._super(...arguments);
this.reset();
},
reset: function() {
this.setProperties(this.attributes);
},
actions: {
submit() {
if (!this.isValid) {
alert('Invalid data. Please review and try again.');
return;
}
let attributes = Object.keys(this.attributes);
let proposal = this.getProperties(attributes);
let saved = this.save(proposal);
// The promise handles inProgress
this.set('inProgress', saved);
saved.then(() => {
this.reset();
window.scroll(0,0);
window.alert('Proposal added.');
});
}
}
});
-44
View File
@@ -1,44 +0,0 @@
<form {{action "submit" on="submit"}}>
<p>
<select required onchange={{action (mut contributorId) value="target.value"}}>
<option value="" selected disabled hidden>Contributor</option>
{{#each contributors as |contributor|}}
<option value={{contributor.id}} selected={{eq contributorId contributor.id}}>{{contributor.github_username}}</option>
{{/each}}
</select>
</p>
<p>
<select required onchange={{action (mut kind) value="target.value"}}>
<option value="community" selected={{eq kind "community"}}>Community</option>
<option value="design" selected={{eq kind "design"}}>Design</option>
<option value="dev" selected={{eq kind "dev"}}>Development</option>
<option value="docs" selected={{eq kind "docs"}}>Documentation</option>
<option value="ops" selected={{eq kind "ops"}}>IT Operations</option>
</select>
</p>
<p>
{{input type="text"
placeholder="100"
value=amount
class=(if isValidAmount "valid" "")}}
</p>
<p>
{{input type="text"
placeholder="Description"
value=description
class=(if isValidDescription "valid" "")}}
</p>
<p>
{{input type="text"
placeholder="URL (optional)"
value=url
class=(if isValidUrl "valid" "")}}
</p>
<p class="actions">
{{input type="submit"
disabled=(is-pending inProgress)
value=(if (is-pending inProgress) "Processing" "Save")}}
{{#link-to "index"}}Back{{/link-to}}
</p>
</form>
@@ -1,64 +0,0 @@
import Component from '@ember/component';
import { computed } from '@ember/object';
let categoryColors = {
community: "#fb6868",
design: "#fbe468",
dev: "#e068fb",
docs: "#97fb68",
ops: "#8f68fb",
}
export default Component.extend({
contributions: null,
chartOptions: Object.freeze({
legend: {
display: false
}
}),
chartData: computed('contributions', function() {
let kredits = this.contributions
.filterBy('vetoed', false)
.map(c => {
return { kind: c.kind, amount: c.amount }
})
.reduce(function (kinds, c) {
if (c.kind in kinds) {
kinds[c.kind] = kinds[c.kind] + c.amount
} else {
kinds[c.kind] = c.amount;
}
return kinds;
}, {});
return {
datasets: [{
data: [
kredits['community'],
kredits['design'],
kredits['dev'],
kredits['ops'],
kredits['docs'],
],
borderColor: [
categoryColors.community,
categoryColors.design,
categoryColors.dev,
categoryColors.ops,
categoryColors.docs,
],
borderWidth: 1
}],
labels: [
'Community',
'Design',
'Development',
'Operations & Infrastructure',
'Documentation'
],
}
})
});
@@ -1,7 +0,0 @@
<div class="chart">
{{ember-chart type="doughnut"
data=chartData
options=chartOptions
width=200
height=200}}
</div>
@@ -1,72 +0,0 @@
import Component from '@ember/component';
import { computed } from '@ember/object';
import { sort } from '@ember/object/computed';
import { isPresent } from '@ember/utils';
import { inject as service } from '@ember/service';
export default Component.extend({
router: service(),
tagName: 'div',
classNames: ['contributions'],
selectedContribution: null,
showQuickFilter: false,
hideSmallContributions: false,
contributorId: null,
contributionKind: null,
kredits: service(),
contributorsSorting: Object.freeze(['name:asc']),
contributors: sort('kredits.contributors', 'contributorsSorting'),
contributorsActive: computed('contributors.[]', 'contributions', function() {
let activeIds = this.contributions.mapBy('contributorId')
.map(id => id.toString())
.uniq();
return this.contributors.filter(c => {
return activeIds.includes(c.id.toString());
});
}),
contributionKinds: computed('contributions.[]', function() {
return this.contributions.mapBy('kind').uniq();
}),
contributionsFiltered: computed('contributions.[]', 'hideSmallContributions', 'contributorId', 'contributionKind', function() {
return this.contributions.filter(c => {
let included = true;
if (this.hideSmallContributions &&
c.amount <= 500) { included = false; }
if (isPresent(this.contributorId) &&
c.contributorId.toString() !== this.contributorId.toString()) { included = false; }
if (isPresent(this.contributionKind) &&
c.kind !== this.contributionKind) { included = false; }
return included;
});
}),
actions: {
veto (contributionId) {
if (this.contractInteractionEnabled) {
this.vetoContribution(contributionId);
} else {
window.alert('Only members can veto contributions. Please ask someone to set you up.');
}
},
openContributionDetails(contribution) {
this.router.transitionTo('dashboard.contributions.show', contribution);
}
}
});
@@ -1,57 +0,0 @@
{{#if showQuickFilter}}
<div class="quick-filter">
<p>
<label class="filter-contributor">
Contributor:
<select onchange={{action (mut contributorId) value="target.value"}}>
<option value="" selected>all</option>
{{#each contributorsActive as |contributor|}}
<option value={{contributor.id}} selected={{eq contributorId contributor.id}}>{{contributor.name}}</option>
{{/each}}
</select>
</label>
<label class="filter-contribution-kind">
Kind:
<select onchange={{action (mut contributionKind) value="target.value"}}>
<option value="" selected>all</option>
{{#each contributionKinds as |kind|}}
<option value={{kind}} selected={{eq contributionKind kind}}>{{capitalize-string kind}}</option>
{{/each}}
</select>
</label>
<label class="filter-contribution-size">
{{input type="checkbox" checked=hideSmallContributions}}
Hide small contributions
</label>
</p>
</div>
{{/if}}
<ul class="contribution-list">
{{#each contributionsFiltered as |contribution|}}
<li role="button" {{action "openContributionDetails" contribution}}
data-contribution-id={{contribution.id}}
class="{{contribution-status contribution}}{{if (eq contribution.id selectedContributionId) " selected"}}">
<p class="meta">
<span class="recipient">{{user-avatar contributor=contribution.contributor}}</span>
<span class="category {{contribution.kind}}">({{contribution.kind}})</span>
<span class="title">{{contribution.description}}</span>
</p>
<p class="kredits-amount">
<span class="amount">{{contribution.amount}}</span><span class="symbol">₭S</span>
</p>
{{#unless contribution.vetoed}}
{{#unless (is-confirmed-contribution contribution)}}
<p class="voting">
{{input type="button" class="button small danger"
click=(action "veto" contribution.id)
disabled=contribution.hasPendingChanges
value="veto"}}
</p>
{{/unless}}
{{/unless}}
</li>
{{/each}}
</ul>
@@ -1,21 +0,0 @@
import Component from '@ember/component';
import { inject as service } from '@ember/service';
export default Component.extend({
router: service(),
tagName: 'table',
classNames: 'contributor-list',
selectedContributorId: null,
actions: {
openContributorDetails(contributor) {
this.router.transitionTo('dashboard.contributors.show', contributor);
}
}
});
@@ -1,20 +0,0 @@
<tbody>
{{#each contributorList as |c|}}
<tr role="button" {{action "openContributorDetails" c.contributor}}
class="{{if (is-current-user c.contributor) "current-user"}} {{if (eq c.contributor.id selectedContributorId) "selected"}}">
<td class="person">
{{user-avatar contributor=c.contributor}} {{c.contributor.name}}
</td>
<td class="kredits">
<span class="amount">
{{#if showUnconfirmedKredits}}
{{c.amountTotal}}
{{else}}
{{c.amountConfirmed}}
{{/if}}
</span>
<span class="symbol">₭S</span>
</td>
</tr>
{{/each}}
</tbody>
@@ -1,15 +0,0 @@
import Component from '@ember/component';
import { computed } from '@ember/object';
export default Component.extend({
tagName: "",
account: null,
iconComponentName: computed('account.site', function() {
if (this.account.site.match(/github|gitea|wiki|zoom/)) {
return 'icon-account-' + this.account.site.replace(/\./g, '-');
} else {
return 'icon-web-globe';
}
})
});
@@ -1,4 +0,0 @@
<a href={{account.url}} target="_blank" rel="noopener" title="{{account.username}} on {{account.site}}">
<span class="site">{{account.site}}</span>
{{component iconComponentName}}
</a>
@@ -1,5 +0,0 @@
import Component from '@ember/component';
export default Component.extend({
tagName: ""
});
@@ -1,6 +0,0 @@
<svg class="icon-gitea" width="400" height="400" version="1.1" viewBox="0 0 400 400" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<g fill-rule="evenodd">
<path d="m235.61 136.7 7e-3 32.7 4.493 2.189c2.471 1.204 4.628 2.25 4.793 2.324s0.3-15.626 0.3-34.889v-35.024h-9.6l7e-3 32.7m-22.336 30.528c-2.787 0.548-5.894 2.175-8.11 4.244-2.296 2.145-1.694 0.967-24.197 47.328l-11.164 23v4.6c0 4.305 0.076 4.75 1.185 6.942 2.815 5.56 1.055 4.606 69.415 37.629l4.2 2.029h4.221c10.104 0 11.144-1.319 26.676-33.8 0.999-2.09 4.15-8.57 7.001-14.4s6.916-14.2 9.033-18.6l3.849-8 0.01-4.219c0.02-8.49-2.644-11.721-14.326-17.371-4.215-2.038-11.264-5.461-15.664-7.606-15.241-7.429-22.802-11.07-23.125-11.137-0.418-0.086-1.177 1.299-5.112 9.333l-3.234 6.6 1.19 2.2c0.654 1.21 1.308 3.038 1.454 4.063l0.265 1.862 5.747 2.8c22.047 10.742 22.975 15.314 9.007 44.377l-3.317 6.902 1.162 2.098c3.865 6.974-0.923 15.098-8.898 15.098-12.557 0-13.717-18.335-1.278-20.2l1.842-0.276 3.101-6.462c12.037-25.079 11.953-25.952-3.232-33.53l-7.333-3.659-2.319 1.032c-1.276 0.567-3.151 1.153-4.167 1.301l-1.848 0.269-6.785 13.855-6.786 13.854 1.109 1.747c6.109 9.633-5.532 20.771-14.552 13.924-6.729-5.108-4.39-16.742 3.633-18.073 0.812-0.134 1.71-0.318 1.996-0.408 0.429-0.136 6.592-12.372 13.118-26.044l1.37-2.87-0.782-1.33c-3.586-6.099 0.331-14.253 7.353-15.306l1.683-0.252 3.969-8.045c2.183-4.425 4.019-8.168 4.08-8.319s-2.979-1.758-6.755-3.571c-8.092-3.885-10.4-4.452-14.685-3.609" />
<path class="fg" d="m73.4 97.876c-2.903 0.376-8.068 1.377-8.8 1.705-0.44 0.197-2.915 1.007-5.5 1.8s-4.7 1.617-4.7 1.831c0 0.213-0.225 0.388-0.5 0.388-0.63 1e-3 -5.615 2.344-5.893 2.771-0.114 0.175-0.837 0.638-1.607 1.029-5.482 2.788-14.835 11.523-18.63 17.4-0.639 0.99-1.274 1.89-1.409 2-0.659 0.534-4.752 8.933-5.555 11.4-0.502 1.54-1.048 2.98-1.213 3.2-0.587 0.782-2.031 7.531-2.489 11.633-0.256 2.292-0.61 4.167-0.785 4.167-0.443 0-0.403 17.45 0.042 18.305 0.199 0.382 0.566 2.748 0.816 5.258 0.493 4.939 1.847 12.516 2.428 13.578 0.198 0.363 0.83 2.369 1.405 4.459 1.927 7.009 10.26 22.927 12.44 23.764 0.303 0.116 0.55 0.481 0.55 0.812 0 0.813 10.667 11.552 12.3 12.383 0.715 0.364 1.3 0.821 1.3 1.017 0 0.195 0.945 0.934 2.1 1.642s2.19 1.41 2.3 1.561 1.28 0.875 2.6 1.609c1.32 0.735 2.67 1.552 3 1.816s1.95 1.086 3.6 1.827c1.65 0.74 3.101 1.486 3.224 1.658 0.123 0.171 1.741 0.865 3.596 1.542s3.557 1.384 3.783 1.572c0.226 0.187 2.388 0.907 4.804 1.599s4.753 1.423 5.193 1.624c1.299 0.593 7.258 1.856 12.2 2.586 2.53 0.374 4.96 0.83 5.4 1.013 1.151 0.48 8.262 1.165 15.067 1.45l5.866 0.247 0.877 2.594c0.903 2.673 4.652 10.529 5.195 10.884 0.168 0.11 0.585 0.83 0.928 1.6 0.685 1.538 1.927 3.686 2.313 4 0.135 0.11 0.826 1.19 1.536 2.4 1.544 2.634 4.561 7.175 5.293 7.968 0.289 0.313 0.975 1.236 1.525 2.051 1.729 2.563 7.039 9.405 8.557 11.025 0.244 0.26 1.523 1.692 2.843 3.183 3.476 3.925 7.354 7.774 10.261 10.183 1.397 1.157 2.629 2.223 2.739 2.368s1.096 0.884 2.191 1.643c1.094 0.758 2.33 1.681 2.745 2.051s1.229 0.911 1.809 1.203 1.884 1.026 2.897 1.632c1.952 1.167 7.201 3.093 8.428 3.093 0.402 0 0.73 0.18 0.73 0.4 0 0.511 115.46 0.557 115.77 0.046 0.121-0.194 1.074-0.482 2.119-0.639 2.437-0.365 7.765-2.307 9.27-3.378 0.64-0.456 1.334-0.829 1.542-0.829 0.451 0 5.639-3.687 8.597-6.111 2.854-2.337 5.633-5.107 8.718-8.689 1.42-1.65 2.681-3.09 2.8-3.2 0.581-0.536 5.161-6.76 5.812-7.9 0.409-0.715 0.869-1.3 1.023-1.3 0.153 0 0.938-1.125 1.742-2.5 2.068-3.533 4.108-6.822 4.561-7.352 0.213-0.248 1.043-1.755 1.845-3.348s1.62-3.1 1.818-3.348c0.687-0.864 5.069-9.661 5.555-11.152 0.269-0.825 0.642-1.5 0.829-1.5s0.878-1.396 1.536-3.101c0.658-1.706 1.671-4.047 2.251-5.203 0.581-1.156 1.405-3.116 1.832-4.356 0.426-1.239 0.934-2.453 1.129-2.696 0.194-0.244 0.946-2.154 1.671-4.244s1.446-3.89 1.602-4c0.155-0.11 0.964-2.36 1.797-5 0.832-2.64 1.627-4.89 1.766-5s0.861-2.27 1.604-4.8c0.742-2.53 1.484-4.782 1.649-5.003 0.164-0.222 0.872-2.562 1.573-5.2 0.701-2.639 1.412-4.977 1.58-5.197s0.965-3.19 1.77-6.6 1.623-6.488 1.817-6.84c0.195-0.353 0.919-3.503 1.611-7 0.692-3.498 1.431-6.678 1.642-7.068 0.211-0.389 0.938-4.169 1.616-8.4 0.677-4.23 1.388-8.052 1.579-8.492 0.192-0.44 0.708-3.77 1.147-7.4 4.258-35.198 1.497-55.451-8.208-60.199l-2.219-1.086-7.473 0.266c-4.111 0.146-7.834 0.417-8.274 0.602-0.801 0.336-13.842 0.941-52 2.412-11.22 0.433-22.2 0.881-24.4 0.997-2.2 0.115-11.334 0.415-20.298 0.665l-16.298 0.455-0.204 69.922-9.392-4.634-8e-3 -65.272-19.3-0.277c-10.615-0.153-19.84-0.441-20.5-0.642-0.66-0.2-6.69-0.551-13.4-0.779-21.82-0.743-58.18-2.495-59-2.843-0.44-0.187-4.04-0.453-8-0.591s-11.34-0.508-16.4-0.822c-8.365-0.519-22.619-0.685-25.6-0.298m13.657 31.23c0.269 0.173 0.809 3.742 1.313 8.694 0.471 4.62 1.021 8.76 1.221 9.2 0.201 0.44 0.561 2.42 0.801 4.4 0.709 5.856 2.382 15.937 2.787 16.8 0.207 0.44 0.943 3.68 1.636 7.2s1.4 6.58 1.571 6.8 0.803 2.56 1.405 5.2c0.601 2.64 1.333 5.34 1.627 6 0.293 0.66 1.193 3.63 2 6.6 0.808 2.97 1.597 5.49 1.754 5.6s0.884 2.27 1.614 4.8c0.731 2.53 1.455 4.69 1.608 4.8 0.154 0.11 0.868 2.09 1.587 4.4 0.72 2.31 1.494 4.429 1.721 4.71 0.226 0.28 0.341 0.567 0.255 0.637-0.263 0.215-9.713-1.339-10.37-1.704-0.337-0.188-1.237-0.468-2-0.623-4-0.814-10.947-2.703-11.712-3.185-0.481-0.304-1.325-0.675-1.875-0.825-1.377-0.377-5.355-1.954-5.6-2.22-0.11-0.12-1.447-0.841-2.971-1.604-1.524-0.762-3.216-1.791-3.759-2.286s-1.16-0.9-1.372-0.9c-1.422 0-11.329-9.68-12.558-12.27-0.347-0.731-0.775-1.33-0.951-1.33-0.593 0-4.638-8.175-5.591-11.3-0.519-1.705-1.071-3.1-1.226-3.1s-0.372-0.495-0.482-1.1c-0.111-0.605-0.599-3.08-1.084-5.5-1.119-5.58-1.528-15.681-0.814-20.111 0.516-3.208 1.895-8.141 2.372-8.489 0.15-0.11 0.752-1.19 1.338-2.4 2.053-4.245 6.611-8.836 11.098-11.177 1.43-0.746 2.69-1.485 2.8-1.643 0.28-0.402 6.231-2.23 8.4-2.58 0.99-0.16 2.003-0.454 2.251-0.654 0.248-0.199 2.678-0.513 5.4-0.697s5.039-0.357 5.149-0.385c0.11-0.029 0.406 0.08 0.657 0.242m131.79 38.066c2.262 0.371 16.092 6.678 15.866 7.236-0.061 0.151-1.897 3.894-4.08 8.319l-3.969 8.045-1.683 0.252c-7.022 1.053-10.939 9.207-7.353 15.306l0.782 1.33-1.37 2.87c-6.526 13.672-12.689 25.908-13.118 26.044-0.286 0.09-1.184 0.274-1.996 0.408-8.023 1.331-10.362 12.965-3.633 18.073 9.02 6.847 20.661-4.291 14.552-13.924l-1.109-1.747 6.786-13.854 6.785-13.855 1.848-0.269c1.016-0.148 2.891-0.734 4.167-1.301l2.319-1.032 7.333 3.659c15.185 7.578 15.269 8.451 3.232 33.53l-3.101 6.462-1.842 0.276c-12.439 1.865-11.279 20.2 1.278 20.2 7.975 0 12.763-8.124 8.898-15.098l-1.162-2.098Line truncated
</g>
</svg>

Before

Width:  |  Height:  |  Size: 7.0 KiB

@@ -1,5 +0,0 @@
import Component from '@ember/component';
export default Component.extend({
tagName: ""
});
@@ -1,8 +0,0 @@
<svg class="icon-github" width="260" height="260" enable-background="new 0 0 212.4575 186.23" version="1.1" viewBox="0 0 260 260" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<g transform="translate(23.766 36.885)">
<path d="m151.79 86.234c-7.078 0.1229-14.154 0.5605-21.232 0.7069-12.318 0.248-24.64 0.5664-36.961 0.512-11.176-0.0472-22.358-0.9728-33.518-0.7052-7.3164 0.1776-14.373 2.2948-20.131 7.584-9.9472 9.1368-12.522 21-11.314 33.807 1.92 20.357 9.2716 31.449 29.115 37.064 15.793 4.4704 31.963 5.2088 48.199 4.9744 5.254 0 10.51 0.1367 15.758-0.0292 12.723-0.4064 25.264-2.2072 37.358-6.3596 10.846-3.7225 18.799-10.691 22.572-22.166 2.6736-8.1288 3.7148-16.388 2.5544-24.853-1.7772-12.959-13.275-30.86-32.4-30.535zm-81.576 59.996c-8.836 0-16-8.9551-16-20 0-11.045 7.164-20 16-20s16 8.9553 16 20c0 11.045-7.164 20-16 20zm76 0c-8.836 0-16-8.9551-16-20 0-11.045 7.164-20 16-20s16 8.9553 16 20c0 11.045-7.164 20-16 20z" fill="none"/>
<path class="fg" d="m200.25 59.188c-2.5076-3.4493-4.3632-6.3888-3.8748-11.44 0.6796-7.0664-0.3536-14.396-1.3204-21.518-1.2188-8.9843-3.5236-17.74-7.1776-26.23-9.0332 1.9356-17.981 3.49-25.963 8.0976-8.4648 4.8908-16.695 10.215-25.08 15.25-0.9532 0.5704-2.3124 0.8848-3.3848 0.7032-17.967-3.1368-35.92-3.0196-53.898-0.086-1.3632 0.2244-3.0724-0.2345-4.2948-0.9608-4.4436-2.6604-8.6564-5.7344-13.123-8.3516-11.656-6.844-23.66-12.822-37.494-14.59-0.3928 0.8597-0.7188 1.4785-0.9612 2.1253-4.164 11.22-6.6424 22.844-7.4276 34.82-0.2872 4.3516-0.6092 8.8048 0 13.072 0.3456 2.4296-4e-3 3.8788-1.3924 5.6132-4.8516 6.0488-8.6368 12.717-11.102 20.219-4.6972 14.295-4.4004 28.861-2.2756 43.475 1.7268 11.974 4.7344 23.537 11.324 33.873 13.186 20.682 32.892 29.774 55.572 31.705 19.308 1.6464 38.8 1.1992 58.213 1.2364 13.855 0.0251 27.57-1.4924 40.715-6.6389 20.375-7.9727 33.859-22.604 40.275-44.166 3.7344-12.545 5.2324-25.396 4.8144-38.498-0.4412-13.81-4.0504-26.566-12.144-37.711zm-18.609 82.435c-3.7736 11.475-11.727 18.444-22.572 22.166-12.094 4.1524-24.635 5.9532-37.358 6.3596-5.248 0.1659-10.504 0.0292-15.758 0.0292-16.236 0.2344-32.406-0.504-48.199-4.9744-19.844-5.6152-27.195-16.707-29.115-37.064-1.2072-12.807 1.3672-24.67 11.314-33.807 5.7576-5.2892 12.814-7.4064 20.131-7.584 11.16-0.2676 22.342 0.658 33.518 0.7052 12.32 0.0544 24.642-0.264 36.961-0.512 7.0784-0.1464 14.154-0.584 21.232-0.7069 19.125-0.3243 30.623 17.576 32.4 30.535 1.1604 8.4647 0.1192 16.724-2.5544 24.853z"/>
<ellipse class="fg" cx="70.214" cy="126.23" rx="16" ry="20"/>
<ellipse class="fg" cx="146.21" cy="126.23" rx="16" ry="20"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.7 KiB

@@ -1,5 +0,0 @@
import Component from '@ember/component';
export default Component.extend({
tagName: ""
});
@@ -1,8 +0,0 @@
<svg class="icon-wiki" width="120" height="120" version="1.1" viewBox="0 0 120 120" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<g transform="translate(18.1,3)">
<polygon class="fg" transform="translate(-6.2,9)" points="6.2 5 45.7 20.5 45.7 91 6.2 75.5"/>
<polygon class="fg" transform="translate(-6.2,9)" points="90 5 50.5 20.5 50.5 91 90 75.5"/>
<polygon class="fg" transform="translate(-6.2,9)" points="87 88 87 81.8 60.4 91"/>
<polygon class="fg" transform="translate(-6.2,9)" points="9.2 88 9.2 81.8 34.9 91"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 703 B

@@ -1,5 +0,0 @@
import Component from '@ember/component';
export default Component.extend({
tagName: ""
});
@@ -1,8 +0,0 @@
<svg width="256" height="256" version="1.1" viewBox="0 0 67.733 67.733" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<g transform="translate(0 -229.27)">
<g transform="matrix(.90278 0 0 .90278 6.5684 141.05)" fill-rule="evenodd">
<path class="fg" d="m32.67 117.1c2.2056 0.1405 3.0528 0.27041 4.1992 0.64479 3.9359 1.2854 6.7418 4.6736 7.3059 8.8223 0.06615 0.48578 0.13996 1.0253 0.16431 1.1986 0.29104 2.0743 0.07488 21.552-0.25003 22.55-0.59082 1.814-1.901 2.7993-4.0537 3.0488-1.3671 0.15849-30.564 0.0701-31.846-0.0963-5.2843-0.68659-8.8934-4.001-9.7398-8.9445-0.38418-2.2439-0.62362-20.748-0.29871-23.084 0.34422-2.4746 1.7264-3.797 4.3212-4.1338 0.98769-0.12832 28.191-0.13361 30.197-6e-3"/>
<path class="fg" d="m61.114 118.11c0.56621 0.4072 0.97816 1.0565 1.1885 1.874 0.19553 0.75909 0.24474 28.04 0.05371 29.747-0.37333 3.3361-2.6305 4.0137-5.5264 1.6584-7.9722-6.4841-9.021-7.5734-9.6795-10.052-0.26008-0.97895-0.33152-10.629-0.08811-11.876 0.38021-1.9457 1.2594-3.1946 3.7383-5.3099 7.4491-6.3564 7.5914-6.4569 9.0522-6.4008 0.70723 0.0272 0.8599 0.0709 1.2613 0.3593"/>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.2 KiB

-5
View File
@@ -1,5 +0,0 @@
import Component from '@ember/component';
export default Component.extend({
tagName: ""
});
-15
View File
@@ -1,15 +0,0 @@
<svg width="60px" height="60px" version="1.1" viewBox="0 0 60 60" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<g fill="none" fill-rule="evenodd">
<g transform="translate(-479,-238)" stroke="#fbe468" stroke-linecap="round" stroke-linejoin="round" stroke-width="1">
<g transform="translate(482,244)">
<a transform="translate(0,2)">
<polygon id="Triangle-58" points="0.15321 44 27 0 53.847 44"/>
</a>
<rect x="25" y="13" width="4" height="21"/>
<a transform="translate(0,2)">
<circle cx="27" cy="38" r="2"/>
</a>
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 750 B

@@ -1,5 +0,0 @@
import Component from '@ember/component';
export default Component.extend({
tagName: ""
});
@@ -1,3 +0,0 @@
<svg class="icon-web-globe" width="60" height="60" enable-background="new 0 0 64 64" version="1.1" viewBox="0 0 60 60" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<path class="fg" d="m48.1 14.3c-0.4-0.5-0.9-1-1.4-1.5-4.3-4.2-10.2-6.8-16.7-6.8s-12.4 2.6-16.7 6.8c-0.5 0.5-1 1-1.4 1.5-3.7 4.2-5.9 9.7-5.9 15.7s2.2 11.5 5.8 15.7c0.4 0.5 0.9 1 1.4 1.5 4.3 4.2 10.3 6.8 16.8 6.8s12.5-2.6 16.8-6.9c0.5-0.5 0.9-0.9 1.4-1.5 3.6-4.1 5.8-9.6 5.8-15.6s-2.2-11.5-5.9-15.7zm3.9 14.7h-8.1c-0.1-3-1-7.3-2.4-10.5 1.8-0.8 3.5-1.8 5.1-3 3.1 3.6 5.1 8.5 5.4 13.5zm-21-20.1c3 2.3 5.8 5.2 7.6 8.5-2.4 0.9-4.6 1.3-7.6 1.4zm-2 9.9c-3-0.1-5.2-0.6-7.6-1.4 1.8-3.3 4.6-6.3 7.6-8.5zm0 2v8.2h-10.8c0.1-3 0.9-6.8 2.3-9.8 2.7 1 5.5 1.5 8.5 1.6zm0 10.2v8c-3 0.1-5.9 0.7-8.6 1.7-1.4-3-2.1-5.7-2.3-9.7zm0 10v10.1c-3-2.3-5.8-5.3-7.7-8.6 2.4-0.9 4.7-1.4 7.7-1.5zm2 0c3 0.1 5.3 0.6 7.7 1.5-1.9 3.4-4.7 6.3-7.7 8.6zm0-2v-8h10.8c-0.1 4-0.9 6.7-2.3 9.7-2.6-1-5.5-1.5-8.5-1.7zm0-10v-8.2c3-0.1 5.8-0.7 8.5-1.6 1.4 3 2.2 6.8 2.3 9.8zm9.5-12.3c-1.7-3.2-4.1-6-6.9-8.3 4.4 0.6 8.4 2.7 11.5 5.6-1.4 1.1-3 1.9-4.6 2.7zm-14.1-8.4c-2.9 2.3-5.2 5.2-6.9 8.3-1.6-0.7-3.2-1.6-4.6-2.6 3.1-2.9 7.1-5 11.5-5.7zm-12.9 7.2c1.6 1.2 3.3 2.2 5.1 3-1.5 3.3-2.3 7.5-2.4 10.5h-8.2c0.3-5 2.3-9.9 5.5-13.5zm-5.5 15.5h8.1c0.1 4 1 7.2 2.4 10.5-1.8 0.8-3.5 1.8-5.1 3-3.2-3.7-5.1-8.5-5.4-13.5zm11.4 12.2c1.7 3.2 4.1 6.1 7 8.4-4.5-0.7-8.5-2.8-11.6-5.8 1.5-1 3-1.8 4.6-2.6zm14.2 8.5c2.9-2.4 5.3-5.2 7-8.4 1.6 0.7 3.2 1.6 4.6 2.6-3.1 3-7.2 5-11.6 5.8zm13-7.3c-1.6-1.2-3.3-2.2-5.1-3 1.4-3.2 2.3-6.5 2.4-10.5h8.1c-0.3 5.1-2.2 9.9-5.4 13.5z"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.7 KiB

@@ -1,7 +0,0 @@
import Component from '@ember/component';
export default Component.extend({
classNames: ['loading-spinner']
});
@@ -1,14 +0,0 @@
<p>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
version="1.1" x="0px" y="0px" viewBox="0 0 132 100"
enable-background="new 0 0 100 100" xml:space="preserve">
<path id="path-comet"
d="M79.062,24.173L79.062,24.173l-0.021-0.011c-0.068-0.03-0.137-0.062-0.204-0.093L42.392,7.337
c0,0,3.065,14.104,4.458,18.019l0,0c0,0-41.754-12.481-46.85-13.67c1.67,6.52,30.607,62.492,30.607,62.492
c5.848,11.873,19.394,18.485,33.522,18.485c19.811,0,35.87-16.059,35.87-35.869C100,42.313,91.418,29.837,79.062,24.173z">
</path>
</svg>
</p>
<p>
Loading data...
</p>
-20
View File
@@ -1,20 +0,0 @@
import Component from '@ember/component';
export default Component.extend({
tagName: 'ul',
classNames: ['proposal-list'],
actions: {
confirm(proposalId) {
if (this.contractInteractionEnabled) {
this.confirmProposal(proposalId);
} else {
window.alert('Only members can vote on proposals. Please ask someone to set you up.');
}
}
}
});
-20
View File
@@ -1,20 +0,0 @@
{{#each proposals as |proposal|}}
<li data-proposal-id={{proposal.id}} class={{if proposal.isExecuted "confirmed" "unconfirmed"}}>
<p class="meta">
<span class="category {{proposal.kind}}">♥ ({{proposal.kind}})</span>
<span class="recipient">{{proposal.contributor.name}}:</span>
</p>
<p class="kredits-amount">
<span class="amount">{{proposal.amount}}</span><span class="symbol">₭S</span>
</p>
<p class="description">
<span class="description">{{proposal.description}}</span>
</p>
<p class="voting">
{{#unless proposal.isExecuted}}
<span class="votes">({{proposal.votesCount}}/{{proposal.votesNeeded}} votes)</span>
<button {{action "confirm" proposal.id}}>+1</button>
{{/unless}}
</p>
</li>
{{/each}}
@@ -1,46 +0,0 @@
import Component from '@ember/component';
import { inject as service } from '@ember/service';
import { computed } from '@ember/object';
import { isPresent } from '@ember/utils';
export default Component.extend({
tagName: '',
kredits: service(),
router: service(),
setupInProgress: false,
userHasEthereumWallet: computed(function() {
return isPresent(window.ethereum);
}),
showConnectButton: computed('userHasEthereumWallet',
'kredits.hasAccounts', function() {
return this.userHasEthereumWallet &&
!this.kredits.hasAccounts;
}),
actions: {
signup() {
this.router.transitionTo('signup');
},
async connectAccount() {
try {
await window.ethereum.enable();
this.set('setupInProgress', true);
await this.kredits.setup();
this.set('setupInProgress', false);
this.router.transitionTo('dashboard');
} catch (error) {
this.set('setupInProgress', false);
console.log('Opening Ethereum wallet failed:', error);
}
}
}
});
@@ -1,18 +0,0 @@
<section id="user-account">
{{#if setupInProgress}}
Connecting account...
{{else}}
{{#if (and kredits.hasAccounts kredits.currentUser)}}
{{kredits.currentUser.name}}
{{#if kredits.currentUserIsCore}}
<span class="core-flag">(core)</span>
{{/if}}
{{else}}
<span class="anonymous">Anonymous</span>
<button {{action "signup"}} class="small">Sign up</button>
{{#if showConnectButton}}
<button {{action "connectAccount"}} class="small green">Connect account</button>
{{/if}}
{{/if}}
{{/if}}
</section>
-30
View File
@@ -1,30 +0,0 @@
import Component from '@ember/component';
import { alias } from '@ember/object/computed';
import { computed } from '@ember/object';
const SIZES = {
'small': '128', // pixels
'medium': '256',
'large': '512'
}
export default Component.extend({
contributor: null,
tagName: 'img',
classNames: ['avatar'],
classNameBindings: ['size'],
attributeBindings: ['src', 'title'],
size: 'small',
src: alias('avatarURL'),
title: alias('contributor.name'),
avatarURL: computed('contributor.github_uid', 'size', function() {
const github_uid = this.contributor.github_uid;
if (github_uid) {
return `https://avatars2.githubusercontent.com/u/${github_uid}?v=3&s=${SIZES[this.size]}`;
}
})
});
View File
Whitespace-only changes.
-6
View File
@@ -1,6 +0,0 @@
import Controller from '@ember/controller';
import { inject as service } from '@ember/service';
export default Controller.extend({
kredits: service(),
});
-30
View File
@@ -1,30 +0,0 @@
import Controller from '@ember/controller';
import { alias, filterBy, sort } from '@ember/object/computed';
import { inject as service } from '@ember/service';
export default Controller.extend({
kredits: service(),
contributors: alias('kredits.contributors'),
minedContributors: filterBy('contributors', 'id'),
contributorsSorting: Object.freeze(['name:asc']),
sortedContributors: sort('minedContributors', 'contributorsSorting'),
actions: {
save (contribution) {
const contributor = this.contributors.findBy('id', contribution.contributorId);
contribution.contributorIpfsHash = contributor.ipfsHash;
return this.kredits.addContribution(contribution)
.then(contribution => {
this.transitionToRoute('index');
return contribution;
});
}
}
});
@@ -1,7 +0,0 @@
import ContributionsNewController from 'kredits-web/controllers/contributions/new';
export default ContributionsNewController.extend({
attributes: null,
});
-16
View File
@@ -1,16 +0,0 @@
import Controller from '@ember/controller';
import { inject as service } from '@ember/service';
export default Controller.extend({
kredits: service(),
actions: {
save (attributes) {
return this.kredits.updateContributor(this.model.id, attributes);
}
}
});
-16
View File
@@ -1,16 +0,0 @@
import Controller from '@ember/controller';
import { inject as service } from '@ember/service';
export default Controller.extend({
kredits: service(),
actions: {
save (contributor) {
return this.kredits.addContributor(contributor);
}
}
});
-63
View File
@@ -1,63 +0,0 @@
import Controller from '@ember/controller';
import { computed } from '@ember/object';
import { alias, not, sort } from '@ember/object/computed';
import { inject as service } from '@ember/service';
export default Controller.extend({
kredits: service(),
showDetailsPane: false,
selectedContributorId: null,
selectedContributionId: null,
currentBlock: alias('kredits.currentBlock'),
contributions: alias('kredits.contributions'),
contributionsConfirmed: alias('kredits.contributionsConfirmed'),
contributionsUnconfirmed: alias('kredits.contributionsUnconfirmed'),
contributionsSorting: Object.freeze(['date:desc', 'time:desc', 'id:desc']),
contributionsUnconfirmedSorted: sort('contributionsUnconfirmed', 'contributionsSorting'),
contributionsConfirmedSorted: sort('contributionsConfirmed', 'contributionsSorting'),
kreditsByContributor: alias('kredits.kreditsByContributor'),
kreditsToplistSorting: computed('showUnconfirmedKredits', function(){
return this.showUnconfirmedKredits ? ['amountTotal:desc'] : ['amountConfirmed:desc'];
}),
kreditsToplist: sort('kreditsByContributor', 'kreditsToplistSorting'),
showUnconfirmedKredits: true,
hideUnconfirmedKredits: not('showUnconfirmedKredits'),
showQuickFilterUnconfirmed: false,
showQuickFilterConfirmed: false,
showIntroText: computed('kredits.{hasAccounts,currentUser}', function(){
return (!this.kredits.hasAccounts || !this.kredits.currentUser);
}),
actions: {
vetoContribution (contributionId) {
this.kredits.veto(contributionId).then(transaction => {
console.debug('[controllers:index] Veto submitted to Ethereum blockhain: '+transaction.hash);
});
},
confirmProposal (proposalId) {
this.kredits.vote(proposalId).then(transaction => {
console.debug('[controllers:index] Vote submitted to Ethereum blockhain: '+transaction.hash);
});
},
toggleQuickFilterUnconfirmed () {
this.toggleProperty('showQuickFilterUnconfirmed');
},
toggleQuickFilterConfirmed () {
this.toggleProperty('showQuickFilterConfirmed');
}
}
});
@@ -1,12 +0,0 @@
import Controller from '@ember/controller';
import { computed } from '@ember/object';
import config from 'kredits-web/config/environment';
export default Controller.extend({
ipfsGatewayUrl: computed(function() {
return config.ipfs.gatewayUrl;
})
});
@@ -1,17 +0,0 @@
import Controller from '@ember/controller';
import { computed } from '@ember/object';
import config from 'kredits-web/config/environment';
export default Controller.extend({
roleName: computed('model.isCore', 'totalKreditsEarned', function() {
if (this.model.isCore) return 'Core Contributor';
if (this.model.totalKreditsEarned <= 5000) return 'Newcomer';
return 'Contributor';
}),
ipfsGatewayUrl: computed(function() {
return config.ipfs.gatewayUrl;
})
});
-24
View File
@@ -1,24 +0,0 @@
import Controller from '@ember/controller';
import { alias, filterBy } from '@ember/object/computed';
import { inject as service } from '@ember/service';
export default Controller.extend({
kredits: service(),
contributors: alias('kredits.contributors'),
minedContributors: filterBy('contributors', 'id'),
actions: {
save(proposal) {
// contributorIpfsHash is needed for the proposal ipfs data. I'm not happy to do this here but I think to load all the contributors in addProposal again is a bit too much. I hope we can refactor it later.
let contributor = this.contributors.findBy('id', proposal.contributorId);
proposal.contributorIpfsHash = contributor.get('ipfsHash');
return this.kredits.addProposal(proposal)
.then((proposal) => {
this.transitionToRoute('index');
return proposal;
});
}
}
});
-49
View File
@@ -1,49 +0,0 @@
import Controller from '@ember/controller';
import { computed } from '@ember/object';
import { alias, not } from '@ember/object/computed';
import { isAddress } from 'web3-utils';
import { inject as service } from '@ember/service';
import config from 'kredits-web/config/environment';
export default Controller.extend({
kredits: service(),
ethAddress: null,
githubAccessToken: alias('kredits.githubAccessToken'),
isValidEthAccount: computed('ethAddress', function() {
return isAddress(this.ethAddress);
}),
signupButtonDisabled: not('isValidEthAccount'),
actions: {
completeSignup () {
const payload = {
accessToken: this.githubAccessToken,
account: this.ethAddress
}
fetch(config.githubSignupUrl, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload)
})
.then(res => res.json())
.then(data => {
console.log('Created contributor:', data);
this.setProperties({
githubAccessToken: null,
ethAddress: null
});
this.transitionToRoute('signup.complete');
});
}
}
});
-14
View File
@@ -1,14 +0,0 @@
import Controller from '@ember/controller';
import config from 'kredits-web/config/environment';
export default Controller.extend({
actions: {
connectGithub () {
window.location = config.githubConnectUrl;
}
}
});
View File
Whitespace-only changes.
-7
View File
@@ -1,7 +0,0 @@
import Helper from '@ember/component/helper';
export default Helper.extend({
compute([string]) {
return string.charAt(0).toUpperCase() + string.slice(1);
}
});
-58
View File
@@ -1,58 +0,0 @@
import Helper from '@ember/component/helper';
import { inject as service } from '@ember/service';
import { alias } from '@ember/object/computed';
import { once } from '@ember/runloop';
export default Helper.extend({
kredits: service(),
currentBlock: alias('kredits.currentBlock'),
compute([contribution]) {
this.setupRecompute(contribution);
let status = [];
if (contribution.vetoed) {
status.push('vetoed');
} else if (contribution.confirmedAt > this.currentBlock) {
status.push('unconfirmed');
} else {
status.push('confirmed');
}
if (contribution.hasPendingChanges) {
status.push('pending');
}
return status.join(' ');
},
destroy () {
if (this.teardown) this.teardown();
this._super(...arguments);
},
setupRecompute (contribution) {
if (this.teardown) this.teardown();
contribution.addObserver('vetoed' , this, this.triggerRecompute);
contribution.addObserver('confirmedAt' , this, this.triggerRecompute);
contribution.addObserver('currentBlock' , this, this.triggerRecompute);
contribution.addObserver('hasPendingChanges' , this, this.triggerRecompute);
this.teardown = () => {
contribution.removeObserver('vetoed', this, this.triggerRecompute);
contribution.removeObserver('confirmedAt', this, this.triggerRecompute);
contribution.removeObserver('currentBlock', this, this.triggerRecompute);
contribution.removeObserver('hadPendingChanges', this, this.triggerRecompute);
};
},
triggerRecompute () {
once(this, function () {
this.recompute();
});
}
});
-15
View File
@@ -1,15 +0,0 @@
import Helper from '@ember/component/helper';
import { inject as service } from '@ember/service';
import { alias } from '@ember/object/computed';
export default Helper.extend({
kredits: service(),
currentBlock: alias('kredits.currentBlock'),
compute([contribution]) {
return !contribution.vetoed &&
(contribution.confirmedAt <= this.currentBlock);
}
});
-16
View File
@@ -1,16 +0,0 @@
import Helper from '@ember/component/helper';
import { inject as service } from '@ember/service';
import { alias } from '@ember/object/computed';
import { isPresent } from '@ember/utils';
export default Helper.extend({
kredits: service(),
currentUser: alias('kredits.currentUser'),
compute([contributor]) {
return isPresent(contributor) && isPresent(this.currentUser) &&
contributor.account === this.currentUser.account;
}
});
-31
View File
@@ -1,31 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Kosmos Kredits</title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
{{content-for "head"}}
<link integrity="" rel="stylesheet" href="{{rootURL}}assets/vendor.css">
<link integrity="" rel="stylesheet" href="{{rootURL}}assets/kredits-web.css">
{{content-for "head-footer"}}
<script>
window.addEventListener('load', function() {
window.windowLoadComplete = true;
});
</script>
</head>
<body>
{{content-for "body"}}
<script src="{{rootURL}}assets/vendor.js"></script>
<script src="{{rootURL}}assets/kredits-web.js"></script>
{{content-for "body-footer"}}
</body>
</html>
View File
Whitespace-only changes.
-46
View File
@@ -1,46 +0,0 @@
import EmberObject, { computed } from '@ember/object';
import { isEmpty, isPresent } from '@ember/utils';
import bignumber from 'kredits-web/utils/cps/bignumber';
import moment from 'moment';
export default EmberObject.extend({
// Contract
id: null,
contributorId: null,
amount: null,
confirmedAt: bignumber('confirmedAtBlock', 'toNumber'),
vetoed: null,
ipfsHash: null,
creatorAccount: null,
// IPFS
kind: null,
description: null,
details: null,
url: null,
date: null,
time: null,
ipfsData: '',
pendingTx: null,
init () {
this._super(...arguments);
if (isEmpty(this.details)) this.set('details', {});
},
iso8601Date: computed('date', 'time', function() {
return this.time ? `${this.date}T${this.time}` : this.date;
}),
jsDate: computed('iso8601Date', function() {
return moment(this.iso8601Date).toDate();
}),
hasPendingChanges: computed('pendingTx', function() {
return isPresent(this.pendingTx);
})
});
-25
View File
@@ -1,25 +0,0 @@
import EmberObject from '@ember/object';
import bignumber from 'kredits-web/utils/cps/bignumber';
import kreditsValue from 'kredits-web/utils/cps/kredits';
export default EmberObject.extend({
// Contract
id: bignumber('idRaw', 'toString'),
account: null,
balance: kreditsValue('balanceRaw'),
totalKreditsEarned: bignumber('totalKreditsEarnedRaw', 'toNumber'),
contributionsCount: bignumber('contributionsCountRaw', 'toNumber'),
isCore: false,
ipfsHash: null,
// IPFS
kind: null,
name: null,
url: null,
github_username: null,
github_uid: null,
wiki_username: null,
zoom_display_name: null,
ipfsData: ''
});
-32
View File
@@ -1,32 +0,0 @@
import EmberObject from '@ember/object';
import { alias } from '@ember/object/computed';
import bignumber from 'kredits-web/utils/cps/bignumber';
export default EmberObject.extend({
// Contract
id: bignumber('idRaw', 'toString'),
creatorAccount: null,
contributorId: bignumber('contributorIdRaw', 'toString'),
amount: bignumber('amountRaw', 'toNumber'),
votesCount: bignumber('votesCountRaw', 'toNumber'),
votesNeeded: bignumber('votesNeededRaw', 'toNumber'),
executed: null,
ipfsHash: null,
// Shortcuts
isExecuted: alias('executed'),
// IPFS
kind: null,
description: null,
details: null,
url: null,
ipfsData: '',
init () {
this._super(...arguments);
this.set('details', {});
}
});
-3
View File
@@ -1,3 +0,0 @@
import Resolver from 'ember-resolver';
export default Resolver;
-37
View File
@@ -1,37 +0,0 @@
import EmberRouter from '@ember/routing/router';
import config from './config/environment';
const Router = EmberRouter.extend({
location: config.locationType,
rootURL: config.rootURL
});
Router.map(function() {
this.route('dashboard', function() {
this.route('contributors', function() {
this.route('show', { path: ':id' });
});
this.route('contributions', function() {
this.route('show', { path: ':id' });
});
});
this.route('proposals', function() {
this.route('new');
});
this.route('contributions', function() {
this.route('new');
this.route('resubmit', { path: ':id/resubmit' });
});
this.route('contributors', function() {
this.route('new');
this.route('edit', { path: ':id/edit' });
});
this.route('signup', function() {
this.route('github');
this.route('eth-account');
this.route('complete');
});
});
export default Router;
View File
Whitespace-only changes.
-26
View File
@@ -1,26 +0,0 @@
import { inject as service } from '@ember/service';
import Route from '@ember/routing/route';
export default Route.extend({
kredits: service(),
beforeModel(/* transition */) {
const kredits = this.kredits;
return kredits.setup().then(() => {
kredits.get('kredits').preflightChecks().catch((error) => {
console.error('Kredits preflight check failed!');
console.error(error);
});
}).catch((error) => {
console.log('Error initializing Kredits', error);
});
},
afterModel() {
return this.kredits.loadInitialData()
.then(() => {
this.kredits.addContractEventHandlers();
});
}
});
-25
View File
@@ -1,25 +0,0 @@
import Route from '@ember/routing/route';
import { inject as service } from '@ember/service';
export default Route.extend({
kredits: service(),
model(params) {
const contribution = this.kredits.contributions.findBy('id', parseInt(params.id));
contribution.contributorId = contribution.contributorId.toString();
return contribution;
},
setupController (controller, model) {
this._super(controller, model);
controller.set('attributes', model.getProperties([
'kind', 'amount', 'description', 'url', 'details'
]));
controller.set('attributes.contributorId', model.contributorId.toString());
controller.set('attributes.date', model.jsDate);
}
});
-30
View File
@@ -1,30 +0,0 @@
import { inject as service } from '@ember/service';
import Route from '@ember/routing/route';
import { alias } from '@ember/object/computed';
export default Route.extend({
kredits: service(),
contributors: alias('kredits.contributors'),
model(params) {
return this.kredits.contributors.findBy('id', params.id);
},
setupController (controller, model) {
this._super(controller, model);
controller.set('attributes', {
account: model.account,
name: model.name,
kind: model.kind,
url: model.url,
github_username: model.github_username,
github_uid: model.github_uid,
gitea_username: model.gitea_username,
wiki_username: model.wiki_username,
zoom_display_name: model.zoom_display_name
});
}
});
@@ -1,32 +0,0 @@
import { inject as service } from '@ember/service';
import Route from '@ember/routing/route';
import { alias } from '@ember/object/computed';
export default Route.extend({
kredits: service(),
contributions: alias('kredits.contributions'),
model (params) {
return this.contributions.findBy('id', parseInt(params.id));
},
setupController (controller, model) {
this._super(controller, model);
this.controllerFor('dashboard')
.setProperties({
showDetailsPane: true,
selectedContributionId: model.id
});
},
deactivate () {
this.controllerFor('dashboard')
.setProperties({
showDetailsPane: false,
selectedContributionId: null
});
}
});
-32
View File
@@ -1,32 +0,0 @@
import { inject as service } from '@ember/service';
import Route from '@ember/routing/route';
import { alias } from '@ember/object/computed';
export default Route.extend({
kredits: service(),
contributors: alias('kredits.contributors'),
model (params) {
return this.contributors.findBy('id', params.id);
},
setupController (controller, model) {
this._super(controller, model);
this.controllerFor('dashboard')
.setProperties({
showDetailsPane: true,
selectedContributorId: model.id
});
},
deactivate () {
this.controllerFor('dashboard')
.setProperties({
showDetailsPane: false,
selectedContributorId: null
});
}
});
-9
View File
@@ -1,9 +0,0 @@
import Route from '@ember/routing/route';
export default Route.extend({
redirect () {
this.transitionTo('dashboard');
}
});
-4
View File
@@ -1,4 +0,0 @@
import Route from '@ember/routing/route';
export default Route.extend({
});
-4
View File
@@ -1,4 +0,0 @@
import Route from '@ember/routing/route';
export default Route.extend({
});
-17
View File
@@ -1,17 +0,0 @@
import Route from '@ember/routing/route';
import { inject as service } from '@ember/service';
import { isEmpty } from '@ember/utils';
export default Route.extend({
kredits: service(),
redirect () {
this._super(...arguments);
if (isEmpty(this.kredits.githubAccessToken)) {
this.transitionTo('signup.index');
}
}
});
-29
View File
@@ -1,29 +0,0 @@
import Route from '@ember/routing/route';
import { inject as service } from '@ember/service';
import { isEmpty } from '@ember/utils';
export default Route.extend({
kredits: service(),
redirect () {
this._super(...arguments);
let accessToken;
try {
accessToken = window.location.hash.match(/access_token=(.+)/)[1];
} catch (error) { /* ignore */ }
if (isEmpty(accessToken) || accessToken === 'undefined') {
console.error('No GitHub access token found.');
this.transitionTo('signup');
return;
}
this.kredits.set('githubAccessToken', accessToken);
this.transitionTo('signup.eth-account');
}
});
-427
View File
@@ -1,427 +0,0 @@
import ethers from 'ethers';
import Kredits from 'kredits-contracts';
import RSVP from 'rsvp';
import Service from '@ember/service';
import EmberObject from '@ember/object';
import { computed } from '@ember/object';
import { alias, notEmpty } from '@ember/object/computed';
import { isEmpty, isPresent } from '@ember/utils';
import groupBy from 'kredits-web/utils/group-by';
import formatKredits from 'kredits-web/utils/format-kredits';
import config from 'kredits-web/config/environment';
import Contributor from 'kredits-web/models/contributor'
import Proposal from 'kredits-web/models/proposal'
import Contribution from 'kredits-web/models/contribution'
export default Service.extend({
currentBlock: null,
currentUserAccounts: null, // default to not having an account. this is the wen web3 is loaded.
currentUser: null,
contributors: null,
contributions: null,
proposals: null,
githubAccessToken: null,
currentUserIsContributor: notEmpty('currentUser'),
currentUserIsCore: alias('currentUser.isCore'),
hasAccounts: notEmpty('currentUserAccounts'),
contributionsUnconfirmed: computed('contributions.[]', 'currentBlock', function() {
return this.contributions.filter(contribution => {
return contribution.confirmedAt > this.currentBlock;
});
}),
contributionsConfirmed: computed('contributions.[]', 'currentBlock', function() {
return this.contributions
.filterBy('vetoed', false)
.filter(contribution => {
return contribution.confirmedAt <= this.currentBlock;
});
}),
kreditsByContributor: computed('contributionsUnconfirmed.@each.vetoed', 'contributors.[]', function() {
const contributionsUnconfirmed = this.contributionsUnconfirmed.filterBy('vetoed', false);
const contributionsGrouped = groupBy(contributionsUnconfirmed, 'contributorId');
const contributorsWithUnconfirmed = contributionsGrouped.map(c => c.value.toString());
const contributorsWithOnlyConfirmed = this.contributors.reject(c => contributorsWithUnconfirmed.includes(c.id))
const kreditsByContributor = contributionsGrouped.map(c => {
const amountUnconfirmed = c.items.mapBy('amount').reduce((a, b) => a + b);
const contributor = this.contributors.findBy('id', c.value.toString());
return EmberObject.create({
contributor: contributor,
amountUnconfirmed: amountUnconfirmed,
amountConfirmed: contributor.totalKreditsEarned,
amountTotal: contributor.totalKreditsEarned + amountUnconfirmed
})
});
contributorsWithOnlyConfirmed.forEach(c => {
kreditsByContributor.push(EmberObject.create({
contributor: c,
amountUnconfirmed: 0,
amountConfirmed: c.totalKreditsEarned,
amountTotal: c.totalKreditsEarned
}));
})
return kreditsByContributor;
}),
init () {
this._super(...arguments);
this.set('contributors', []);
this.set('proposals', []);
this.set('contributions', []);
},
// This is called in the application route's beforeModel(). So it is
// initialized before everything else, and we can rely on the ethProvider and
// the potential currentUserAccounts to be available
getEthProvider () {
let ethProvider;
return new RSVP.Promise(async (resolve) => {
function instantiateWithoutAccount () {
console.debug('[kredits] Creating new instance from npm module class');
console.debug(`[kredits] providerURL: ${config.web3ProviderUrl}`);
ethProvider = new ethers.providers.JsonRpcProvider(config.web3ProviderUrl);
resolve({
ethProvider: ethProvider,
ethSigner: null
});
}
async function instantiateWithAccount (web3Provider, context) {
console.debug('[kredits] Using user-provided instance, e.g. from Mist browser or Metamask');
ethProvider = new ethers.providers.Web3Provider(web3Provider);
const network = await ethProvider.getNetwork();
if (isPresent(config.web3RequiredNetwork) &&
network.name !== config.web3RequiredNetwork) {
window.alert(`Please switch your Ethereum wallet to the "${config.web3RequiredNetwork}" network before connecting your account.`);
return instantiateWithoutAccount();
}
ethProvider.listAccounts().then(accounts => {
context.set('currentUserAccounts', accounts);
const ethSigner = accounts.length === 0 ? null : ethProvider.getSigner();
resolve({
ethProvider,
ethSigner
});
});
}
if (window.ethereum) {
if (window.ethereum.isConnected()) {
instantiateWithAccount(window.ethereum, this);
} else {
instantiateWithoutAccount();
}
}
// Legacy dapp browsers...
else if (window.web3) {
instantiateWithAccount(window.web3.currentProvider, this);
}
// Non-dapp browsers...
else {
instantiateWithoutAccount();
}
});
},
setup () {
return this.getEthProvider().then((providerAndSigner) => {
let kredits = new Kredits(providerAndSigner.ethProvider, providerAndSigner.ethSigner, {
addresses: { Kernel: config.kreditsKernelAddress },
apm: config.kreditsApmDomain,
ipfsConfig: config.ipfs
});
return kredits
.init()
.then(async (kredits) => {
this.set('kredits', kredits);
this.set('currentBlock', await kredits.provider.getBlockNumber());
if (this.currentUserAccounts && this.currentUserAccounts.length > 0) {
this.getCurrentUser.then((contributorData) => {
this.set('currentUser', contributorData);
});
}
return kredits;
});
});
},
totalSupply: computed(function() {
return this.kredits.Token.functions.totalSupply().then(total => {
return formatKredits(total);
})
}),
totalKreditsEarned: computed(function() {
return this.kredits.Contribution.functions.totalKreditsEarned(true)
.then(total => total.toNumber());
}),
loadInitialData () {
return this.getContributors()
.then(contributors => this.contributors.pushObjects(contributors))
.then(() => this.getContributions())
.then(contributions => this.contributions.pushObjects(contributions))
},
addContributor (attributes) {
if (attributes.github_uid) {
const uidInt = parseInt(attributes.github_uid);
attributes.github_uid = uidInt;
}
console.debug('[kredits] add contributor', attributes);
return this.kredits.Contributor.add(attributes, { gasLimit: 350000 })
.then(data => {
console.debug('[kredits] add contributor response', data);
});
},
updateContributor (id, attributes) {
if (attributes.github_uid) {
const uidInt = parseInt(attributes.github_uid);
attributes.github_uid = uidInt;
}
console.debug('[kredits] update contributor', attributes);
return this.kredits.Contributor.updateProfile(id, attributes, { gasLimit: 350000 })
.then(data => {
console.debug('[kredits] updateProfile response', data);
});
},
getContributors () {
return this.kredits.Contributor.all()
.then(contributors => {
return contributors.map(contributor => {
return Contributor.create(contributor);
});
});
},
addContribution (attributes) {
console.debug('[kredits] add contribution', attributes);
return this.kredits.Contribution.addContribution(attributes, { gasLimit: 300000 })
.then(data => {
console.debug('[kredits] add contribution response', data);
attributes.contributor = this.contributors.findBy('id', attributes.contributorId);
const contribution = Contribution.create(attributes);
contribution.set('pendingTx', data);
contribution.set('confirmedAtBlock', data.blockNumber + 40320);
this.contributions.pushObject(contribution);
return contribution;
});
},
//
// TODO Implement proposals with voting
//
// addProposal (attributes) {
// console.debug('[kredits] add proposal', attributes);
//
// return this.kredits.Proposal.addProposal(attributes)
// .then((data) => {
// console.debug('[kredits] add proposal response', data);
// attributes.contributor = this.contributors.findBy('id', attributes.contributorId);
// return Proposal.create(attributes);
// });
// },
// getProposals () {
// return this.kredits.Proposal.all()
// .then(proposals => {
// return proposals.map(proposal => {
// proposal.contributor = this.contributors.findBy('id', proposal.contributorId.toString());
// return Proposal.create(proposal);
// });
// });
// },
getContributions () {
return this.kredits.Contribution.all({page: {size: 200}})
.then(contributions => {
return contributions.map(contribution => {
contribution.contributor = this.contributors.findBy('id', contribution.contributorId.toString());
return Contribution.create(contribution);
});
});
},
vote (proposalId) {
console.debug('[kredits] vote for', proposalId);
return this.kredits.Proposal.functions.vote(proposalId)
.then(data => {
console.debug('[kredits] vote response', data);
return data;
});
},
veto (contributionId) {
console.debug('[kredits] veto against', contributionId);
const contribution = this.contributions.findBy('id', contributionId);
return this.kredits.Contribution.functions.veto(contributionId, { gasLimit: 300000 })
.then(data => {
console.debug('[kredits] veto response', data);
contribution.set('pendingTx', data);
return data;
});
},
getCurrentUser: computed('kredits.provider', function() {
if (isEmpty(this.currentUserAccounts)) {
return RSVP.resolve();
}
return this.kredits.Contributor
.functions.getContributorIdByAddress(this.get('currentUserAccounts.firstObject'))
.then((id) => {
// check if the user is a contributor or not
if (id === 0) {
return RSVP.resolve();
} else {
return this.kredits.Contributor.getById(id);
}
});
}),
findProposalById(proposalId) {
return this.proposals.findBy('id', proposalId.toString());
},
// Contract events
addContractEventHandlers () {
this.kredits.Contributor
.on('ContributorProfileUpdated', this.handleContributorChange.bind(this))
.on('ContributorAccountUpdated', this.handleContributorChange.bind(this))
.on('ContributorAdded', this.handleContributorChange.bind(this))
this.kredits.Contribution
.on('ContributionAdded', this.handleContributionAdded.bind(this))
.on('ContributionVetoed', this.handleContributionVetoed.bind(this))
this.kredits.Proposal
.on('ProposalCreated', this.handleProposalCreated.bind(this))
.on('ProposalVoted', this.handleProposalVoted.bind(this))
.on('ProposalExecuted', this.handleProposalExecuted.bind(this));
this.kredits.Token
.on('Transfer', this.handleTransfer.bind(this));
},
async handleContributorChange (contributorId, ...args) {
console.debug('[kredits] Contributor add/update event received for ID', contributorId);
console.debug('[kredits] Event data:', args);
const contributorData = await this.kredits.Contributor.getById(contributorId);
const newContributor = Contributor.create(contributorData);
const oldContributor = this.contributors.findBy('id', contributorId.toString());
if (oldContributor) {
console.debug('[kredits] old contributor', oldContributor);
this.contributors.removeObject(oldContributor);
}
console.debug('[kredits] new contributor', newContributor);
this.contributors.pushObject(newContributor);
},
async handleContributionAdded (id, contributorId, amount) {
console.debug('[kredits] ContributionAdded event received', { id, contributorId, amount });
const pendingContribution = this.contributions.find(c => {
return (c.id === null) &&
(c.contributorId.toString() === contributorId.toString()) &&
(c.amount.toString() === amount.toString());
});
if (pendingContribution) {
const attributes = await this.kredits.Contribution.getById(id);
attributes.contributor = this.contributors.findBy('id', attributes.contributorId.toString());
const newContribution = Contribution.create(attributes);
this.contributions.addObject(newContribution);
this.contributions.removeObject(pendingContribution);
}
},
handleContributionVetoed (contributionId) {
console.debug('[kredits] ContributionVetoed event received for ', contributionId);
const contribution = this.contributions.findBy('id', contributionId);
console.debug('[kredits] contribution', contribution);
if (contribution) {
contribution.set('vetoed', true);
contribution.set('pendingTx', null);
}
},
handleProposalCreated (proposalId) {
let proposal = this.findProposalById(proposalId);
if (proposal) {
console.debug('[events] proposal exists, not adding from event');
return;
}
this.kredits.Proposal.getById(proposalId)
.then((proposal) => {
proposal.contributor = this.contributors.findBy('id', proposal.contributorId.toString());
this.proposals.pushObject(Proposal.create(proposal));
});
},
// TODO: We may want to reload that proposal to show the voter as voted
handleProposalVoted (proposalId, voterId, totalVotes) {
let proposal = this.findProposalById(proposalId);
if (proposal) {
proposal.set('votesCount', totalVotes);
}
},
handleProposalExecuted (proposalId, contributorId, amount) {
let proposal = this.findProposalById(proposalId);
if (proposal.get('isExecuted')) {
console.debug('[events] proposal already executed, not adding from event');
return;
}
proposal.set('executed', true);
this.contributors
.findBy('id', contributorId.toString())
.incrementProperty('balance', amount);
},
handleTransfer (from, to, value) {
value = value.toNumber();
this.contributors
.findBy('address', from)
.decrementProperty('balance', value);
this.contributors
.findBy('address', to)
.incrementProperty('balance', value);
},
});
-73
View File
@@ -1,73 +0,0 @@
button, input[type=submit], .button {
display: inline-block;
padding: 0.6rem 2rem;
background-color: rgba(22, 21, 40, 0.6);
border: 1px solid rgba(22, 21, 40, 1);
border-radius: 3px;
color: $primary-color;
font-weight: 500;
text-decoration: none;
text-transform: uppercase;
cursor: pointer;
letter-spacing: 0.1em;
&+button, &+input[type=submit], &+.button {
margin-left: 0.5rem;
}
&:hover {
background-color: rgba(22, 21, 40, 0.8);
}
&:active, &.active {
border-color: $primary-color;
}
&[disabled] {
color: rgba(255,255,255,0.5);
}
&.small {
font-size: 0.86rem;
padding: 0.2rem 0.8rem;
}
&.danger:not(:disabled) {
color: $red;
background-color: rgba(40, 21, 21, 0.6);
border-color: rgba(40, 21, 21, 1);
&:hover {
background-color: rgba(40, 21, 21, 0.8);
}
&:active, &.active {
border-color: $red;
}
}
&.green:not(:disabled) {
color: $green;
background-color: rgba(21, 40, 21, 0.6);
border-color: rgba(21, 40, 21, 1);
&:hover {
background-color: rgba(21, 40, 21, 0.8);
}
&:active, &.active {
border-color: $green;
}
}
&.icon {
svg {
width: 2rem;
height: 2rem;
vertical-align: middle;
margin-right: 1rem;
.fg {
fill: $primary-color;
}
}
}
}
-10
View File
@@ -1,10 +0,0 @@
$blue: #68d7fb;
$purple: #8f68fb;
$pink: #e068fb;
$green: #97fb68;
$yellow: #fbe468;
$red: #fb6868;
$primary-color: $blue;
$body-text-color: #fff;
-116
View File
@@ -1,116 +0,0 @@
section#add-contributor,
section#add-contribution,
section#add-proposal,
section#signup {
form {
p {
margin-bottom: 1.5rem;
&.mg-bottom-md {
margin-bottom: 2rem;
}
&.label {
margin-bottom: .5rem;
}
&.actions {
padding-top: 1.5rem;
text-align: center;
a {
color: $primary-color;
margin-left: 1rem;
}
}
}
label {
display: block;
margin-bottom: 0.5rem;
opacity: 0.7;
}
input[type=text], select {
width: 100%;
padding: 1rem;
border: none;
border-bottom: 1px solid rgba(255,255,255,0.2);
background-color: rgba(22, 21, 40, 0.3);
color: #fff;
font-size: 1.2rem;
transition: border-color 0.1s linear;
&:focus, &.valid {
background-color: rgba(22, 21, 40, 0.6);
}
&:focus {
border-color: $blue;
}
&::placeholder {
color: rgba(238, 238, 238, 0.5);
}
}
select {
-moz-appearance: none;
-webkit-appearance: none;
appearance: none;
border-radius: 0;
background-color: rgba(22, 21, 40, 0.6);
background-image:
linear-gradient(45deg, transparent 50%, gray 50%),
linear-gradient(135deg, gray 50%, transparent 50%);
background-position:
calc(100% - 1.5rem) calc(1rem + 0.5rem),
calc(100% - 1rem) calc(1rem + 0.5rem);
background-size:
0.5rem 0.5rem,
0.5rem 0.5rem;
background-repeat: no-repeat;
&:invalid {
color: rgba(238, 238, 238, 0.5);
}
}
input[type=submit] {
padding: 0.6rem 2rem;
&:disabled {
background-color: transparent;
}
}
input[type=checkbox] {
display: none;
}
label.checkbox {
line-height: 3.2rem;
font-size: 1.2rem;
&::before {
display: inline-block;
margin-right: 0.8rem;
height: 3.2rem;
width: 3.2rem;
font-size: 2rem;
background-color: rgba(22, 21, 40, 0.3);
border-bottom: 1px solid rgba(255,255,255,0.2);
text-align: center;
vertical-align: middle;
content: '✓';
color: rgba(255,255,255,0.2);
}
}
input[type=checkbox]:checked + label.checkbox {
&::before {
background-color: rgba(22, 21, 40, 0.6);
color: #fff;
}
}
}
}
-154
View File
@@ -1,154 +0,0 @@
main {
padding: 1rem 2rem;
@include media-max(small) {
padding: 1rem;
}
&#dashboard {
width: 100%;
display: grid;
grid-row-gap: 2rem;
grid-template-areas:
"stats"
"contributions";
}
&.center-column {
display: flex;
flex-direction: column;
align-items: center;
section {
width: 600px;
max-width: 100%;
header {
text-align: center;
}
}
}
section {
.content {
a {
font-size: inherit;
}
&.text-lg {
p {
font-size: 1.2rem;
margin-bottom: 1em;
line-height: 1.5em;
}
}
&.text-center {
text-align: center;
}
p {
&.mg-bottom-md {
margin-bottom: 2rem;
}
&.actions {
text-align: center;
padding-top: 2rem;
}
}
}
}
}
#intro {
padding: 2rem;
background-color: rgba(0,0,0,.2);
font-size: 1.6rem;
@include media-max(small) {
padding: 2rem 1rem;
font-size: 1.4rem;
}
h2 {
font-size: inherit;
margin-bottom: 1em;
}
p {
margin-bottom: 1em;
line-height: 1.5em;
font-size: 1.2rem;
&:last-child {
margin-bottom: 0;
}
}
a {
text-decoration: none;
&:hover, &:active {
text-decoration: underline;
}
}
}
@media (min-width: 550px) {
main {
&#dashboard {
grid-column-gap: 4rem;
grid-row-gap: 2rem;
grid-template-columns: 2fr 4fr;
grid-template-areas:
"stats contributions";
&.with-details {
grid-column-gap: 3rem;
grid-template-columns: 2fr 4fr 2fr;
grid-template-areas:
"stats contributions details";
}
}
}
}
main section {
margin-bottom: 5rem;
&:first-of-type {
margin-top: 2rem;
}
@include media-max(small) {
margin-bottom: 5rem;
}
header {
margin-bottom: 3rem;
&.with-nav {
display: grid;
grid-template-columns: auto 5rem;
grid-template-areas:
"title" "actions";
}
h2 {
display: inline-block;
// padding-left: 1.2rem;
}
nav {
display: flex;
flex-direction: row;
align-items: center;
justify-content: flex-end;
}
@include media-max(small) {
margin-bottom: 2rem;
}
}
}
-33
View File
@@ -1,33 +0,0 @@
$breakpoints-max: (
small: 600px,
medium: 960px,
large: 1280px
);
$breakpoints-min: (
small: 601px,
medium: 961px,
large: 1281px
);
@mixin media-max($screen-size) {
@if map-has-key($breakpoints-max, $screen-size) {
@media (max-width: map-get($breakpoints-max, $screen-size)) {
@content;
}
} @else {
// Debugging
@warn "'#{$screen-size}' has not been declared as a breakpoint."
}
}
@mixin media-min($screen-size) {
@if map-has-key($breakpoints-min, $screen-size) {
@media (min-width: map-get($breakpoints-min, $screen-size)) {
@content;
}
} @else {
// Debugging
@warn "'#{$screen-size}' has not been declared as a breakpoint."
}
}
-117
View File
@@ -1,117 +0,0 @@
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
*:hover, *:active, *:focus {
outline: none;
-webkit-tap-highlight-color: rgba(255, 255, 255, 0);
-webkit-tap-highlight-color: transparent;
}
@import "mediaqueries";
@import "layout";
@import "colors";
$font-family-sans: 'Open Sans', sans-serif;
html, body {
font-family: $font-family-sans;
font-weight: 300;
font-size: 12px;
color: $body-text-color;
}
body {
background-image: linear-gradient(to bottom, rgba(22, 21, 40, .4), rgba(0, 0, 0, .75)), url('/img/bg.jpg');
background-repeat: none;
background-attachment: fixed;
}
@media screen and (min-width: 900px) {
body {
background-size: cover;
}
}
h1, h2, h3, h4, h5, input, button {
font-family: $font-family-sans;
font-size: 1rem;
font-weight: 300;
}
a {
color: $primary-color;
}
section {
h2 {
font-size: 1.4rem;
color: $primary-color;
}
&#people {
.content {
p.stats {
margin-bottom: 1rem;
font-size: 1rem;
color: white;
text-align: center;
span.number {
font-weight: 600;
}
}
}
}
&#contributions-by-type {
.chart {
width: 50%;
margin-left: auto;
margin-right: auto;
@include media-max(small) {
width: 75%;
}
}
}
&#proposals-open, &#proposals-closed {
.actions {
padding-top: 3rem;
font-size: 1rem;
color: $primary-color;
text-align: center;
@include media-max(small) {
padding-top: 2rem;
}
a {
color: $primary-color;
}
}
}
}
@media (min-width: 550px) {
section {
h2 {
font-size: 2rem;
}
}
}
@import "buttons";
@import "forms";
@import "components/contribution-list";
@import "components/contribution-details";
@import "components/contributor-list";
@import "components/contributor-profile";
@import "components/external-account-link";
@import "components/loading-spinner";
@import "components/proposal-list";
@import "components/topbar";
@import "components/topbar-account-panel";
@import "components/user-avatar";
@@ -1,88 +0,0 @@
section#contribution-details {
header {
nav {
.amount {
font-size: 1.5rem;
}
.symbol {
padding-left: 0.2rem;
}
}
}
.content {
width: 100%;
margin: 0 0 1.5rem;
padding: 2rem 2rem;
border-top: 1px solid rgba(255,255,255,0.2);
border-bottom: 1px solid rgba(255,255,255,0.2);
background-color: rgba(255,255,255,0.1);
h3 {
font-size: 1.5rem;
margin-bottom: 2rem;
}
p {
margin-bottom: 2rem;
span {
}
&.who-what-when {
font-size: 1.2rem;
margin-bottom: 1.2rem;
}
&:last-of-type {
margin-bottom: 0;
}
}
a:not(.button) {
color: $primary-color;
text-decoration: none;
&:not(.button):hover {
text-decoration: underline;
}
}
}
.actions {
text-align: center;
}
&.vetoed {
.content {
h3 {
text-decoration: line-through;
}
}
}
.hint.vetoed {
overflow: auto;
margin-top: 2rem;
padding-top: 2rem;
border-top: 1px solid rgba(255,255,255,0.2);
font-size: 1.2rem;
.icon {
display: inline-block;
width: 40px;
height: 40px;
float: left;
margin-right: 1rem;
margin-bottom: 1rem;
svg {
width: 100%;
height: auto;
}
}
}
}
@@ -1,151 +0,0 @@
main section {
@include media-max(small) {
&#contributions-unconfirmed, &#contributions-confirmed {
margin-top: 0;
}
}
}
.quick-filter {
font-size: 1.2rem;
margin-bottom: 2rem;
p {
padding: 0.2rem 0 0;
}
label {
&+ label {
margin-left: 3.6rem;
}
}
}
ul.contribution-list {
clear: both;
width: 100%;
list-style: none;
li {
display: grid;
grid-template-columns: auto 5rem 5rem;
grid-row-gap: 0.5rem;
padding: 0.8rem 1.2rem;
background-color: rgba(255,255,255,0.1);
font-size: 1.2rem;
border-bottom: 1px solid rgba(255,255,255,0.2);
cursor: pointer;
&:first-of-type {
border-top: 1px solid rgba(255,255,255,0.2);
}
&.confirmed {
grid-template-columns: auto 5rem;
}
&.vetoed {
grid-template-columns: auto 5rem;
text-decoration: line-through;
opacity: 0.6;
}
&.selected {
background-color: rgba(255,255,255,0.2);
}
p {
align-self: center;
margin: 0;
line-height: 2rem;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
&.kredits-amount, &.voting {
text-align: right;
}
}
span {
&.title {
a {
text-decoration: none;
color: $body-text-color;
}
a:hover, a:active {
color: $primary-color;
}
}
}
.description {
line-height: 1.4em;
font-size: 1rem;
}
.category {
color: $blue;
padding-right: 0.2rem;
&.community { color: $red; }
&.dev { color: $pink; }
&.design { color: $yellow; }
&.docs { color: $green; }
&.ops { color: $purple; }
}
.amount {
font-weight: 500;
}
.symbol {
font-size: 0.8rem;
padding-left: 0.2rem;
}
.recipient {
font-weight: 500;
}
.votes {
font-size: 1rem;
color: $primary-color;
margin-right: 0.5rem;
}
}
}
@media (min-width: 550px) {
ul.proposal-list {
li {
grid-template-columns: auto 10rem;
grid-row-gap: 0.5rem;
p {
&.kredits-amount, &.voting {
text-align: right;
}
}
&.unconfirmed {
p {
&.kredits-amount, &.voting {
text-align: right;
}
&.description {
grid-column-start: span 1;
}
&.voting {
grid-column-start: span 1;
}
}
}
.description {
}
}
}
}
@@ -1,51 +0,0 @@
table.contributor-list {
width: 100%;
border-collapse: collapse;
margin-bottom: 1.5rem;
tr {
background-color: rgba(255,255,255,0.1);
border-bottom: 1px solid rgba(255,255,255,0.2);
cursor: pointer;
&:first-of-type {
border-top: 1px solid rgba(255,255,255,0.2);
}
&.selected {
background-color: rgba(255,255,255,0.2);
}
&.current-user {
font-weight: 500;
}
td {
padding: 0 1.2rem;
line-height: 3.6rem;
&.person {
text-align: left;
font-size: 1.2rem;
img.avatar {
margin-right: 0.2rem;
}
}
&.kredits {
text-align: right;
.amount {
font-size: 1.2rem;
font-weight: 500;
}
.symbol {
font-size: 0.8rem;
padding-left: 0.2rem;
}
}
}
}
}
@@ -1,52 +0,0 @@
section#contributor-profile {
text-align: center;
header {
z-index: 2;
width: 100%;
text-align: center;
img {
margin: 0 auto;
border: 3px solid rgba(255,255,255,0.2);
}
}
.content {
z-index: 1;
width: 100%;
margin: -7.2rem 0 1.5rem;
padding: 6rem 1.2rem 2rem;
border-top: 1px solid rgba(255,255,255,0.2);
border-bottom: 1px solid rgba(255,255,255,0.2);
background-color: rgba(255,255,255,0.1);
h2 {
text-align: center;
margin-bottom: 0.6rem;
}
p.role {
margin-bottom: 2rem;
}
ul.external-accounts {
list-style: none;
li {
display: inline-block;
&+li {
margin-left: 0.6rem;
}
}
}
}
.actions {
.button {
margin-bottom: 0.6rem;
}
}
}
@@ -1,34 +0,0 @@
.external-accounts a {
display: inline-block;
width: 4rem;
height: 4rem;
padding: 0.8rem;
background-color: rgba(0, 0, 0, 0.3);
color: $body-text-color;
border-radius: 2rem;
span.site {
display: none;
}
svg {
display: block;
position: relative;
width: 100%;
height: 100%;
.fg {
fill: $body-text-color;
}
}
&:hover, &:active {
background-color: rgba(0, 0, 0, 0.5);
svg {
.fg {
fill: $primary-color;
}
}
}
}
@@ -1,37 +0,0 @@
@keyframes pulse {
from {
opacity: 0.1;
}
to {
opacity: 0.6;
}
}
.loading-spinner {
margin-top: 12rem;
text-align: center;
font-size: 1.4rem;
color: $primary-color;
@include media-max(small) {
margin-top: 6rem;
}
svg {
width: 200px;
height: 200px;
margin-bottom: 2rem;
#path-comet {
fill: $primary-color;
opacity: 0.1;
animation-name: pulse;
animation-iteration-count: infinite;
animation-timing-function: ease-in-out;
animation-direction: alternate;
animation-duration: 1s;
}
}
}
-111
View File
@@ -1,111 +0,0 @@
ul.proposal-list {
clear: both;
width: 100%;
list-style: none;
li {
display: grid;
grid-template-columns: auto 5rem;
grid-row-gap: 0.5rem;
padding: 1rem 1.2rem;
background-color: rgba(255,255,255,0.1);
font-size: 1.2rem;
border-bottom: 1px solid rgba(255,255,255,0.2);
&:first-of-type {
border-top: 1px solid rgba(255,255,255,0.2);
}
p {
align-self: center;
margin: 0;
line-height: 2rem;
&.kredits-amount, &.voting {
text-align: right;
}
&.description {
grid-column-start: span 2;
}
&.voting {
grid-column-start: span 2;
}
}
span {
}
.description {
line-height: 1.4em;
font-size: 1rem;
}
.category {
color: $blue;
padding-right: 0.2rem;
&.community { color: $red; }
&.dev { color: $pink; }
&.design { color: $yellow; }
&.docs { color: $green; }
&.ops { color: $purple; }
}
.amount {
font-weight: 500;
}
.symbol {
font-size: 1rem;
font-weight: 500;
padding-left: 0.2rem;
}
.recipient {
font-weight: 500;
}
.votes {
font-size: 1rem;
color: $primary-color;
margin-right: 0.5rem;
}
}
}
@media (min-width: 550px) {
ul.proposal-list {
li {
grid-template-columns: auto 10rem;
grid-row-gap: 0.5rem;
p {
&.kredits-amount, &.voting {
text-align: right;
}
}
&.unconfirmed {
p {
&.kredits-amount, &.voting {
text-align: right;
}
&.description {
grid-column-start: span 1;
}
&.voting {
grid-column-start: span 1;
}
}
}
.description {
}
}
}
}
@@ -1,17 +0,0 @@
header#topbar section#user-account {
button {
margin-left: 1.5rem;
}
button + button {
margin-left: 0.6rem;
}
@include media-max(small) {
.anonymous {
display: none;
}
}
}
-27
View File
@@ -1,27 +0,0 @@
#topbar {
padding: 0 1rem;
height: 3rem;
line-height: 3rem;
background-color: rgba(0,0,0,.3);
@include media-min(medium) {
padding: 0 2rem;
height: 4rem;
line-height: 4rem;
}
h1 {
display: inline-block;
text-transform: uppercase;
a {
color: inherit;
text-decoration: none;
}
}
section#user-account {
display: inline-block;
float: right;
}
}
-21
View File
@@ -1,21 +0,0 @@
img.avatar {
width: 2rem;
height: 2rem;
vertical-align: middle;
margin-right: 0.2rem;
border-radius: 1rem;
&.medium {
margin: 0;
width: 10rem;
height: 10rem;
border-radius: 5rem;
}
&.large {
margin: 0;
width: 256px;
height: 256px;
border-radius: 128px;
}
}
-1
View File
@@ -1 +0,0 @@
{{loading-spinner}}
-6
View File
@@ -1,6 +0,0 @@
<header id="topbar">
<h1>{{link-to "Kosmos Kredits" "dashboard"}}</h1>
{{topbar-account-panel}}
</header>
{{outlet}}
Loaded 100 of 267 files, more files were not shown because too many files have changed in this diff. Show more