├── CHANGELOG
├── README.md
├── .gitignore
├── favicon.ico
├── src
├── api
│ ├── .vscode
│ │ └── settings.json
│ ├── .gitignore
│ ├── handler.ts
│ ├── events
│ │ └── basic.json
│ ├── package.json
│ ├── kitty
│ │ └── getKittyRecommendations.ts
│ └── serverless.yml
├── index.d.ts
├── index.tsx
├── utils.ts
├── __tests__
│ └── App.test.tsx
├── components
│ ├── Genes.ts
│ ├── Cryptokitty.tsx
│ └── About.tsx
├── cattributes
│ ├── colors.ts
│ ├── eye
│ │ ├── googly.svg
│ │ ├── fabulous.svg
│ │ ├── simple.svg
│ │ ├── raisedbrow.svg
│ │ ├── crazy.svg
│ │ ├── thicccbrowz.svg
│ │ ├── otaku.svg
│ │ └── wingtips.svg
│ ├── mouth
│ │ ├── soserious.svg
│ │ ├── gerbil.svg
│ │ ├── happygokitty.svg
│ │ ├── whixtensions.svg
│ │ ├── saycheese.svg
│ │ ├── pouty.svg
│ │ ├── tongue.svg
│ │ ├── dali.svg
│ │ └── beard.svg
│ └── body
│ │ ├── laperm-totesbasic.svg
│ │ ├── laperm-spock.svg
│ │ ├── laperm-calicool.svg
│ │ └── munchkin-totesbasic.svg
└── App.tsx
├── tslint.json
├── tsconfig.json
├── webpack.config.js
├── index.html
└── package.json
/CHANGELOG:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /node_modules
2 | SECRETS
--------------------------------------------------------------------------------
/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/achadha235/cryptokitty-designer/HEAD/favicon.ico
--------------------------------------------------------------------------------
/src/api/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "eslint.enable": false,
3 | "jshint.enable": false,
4 | "tslint.enable": false
5 | }
--------------------------------------------------------------------------------
/src/api/.gitignore:
--------------------------------------------------------------------------------
1 | # package directories
2 | node_modules
3 | jspm_packages
4 |
5 | # Serverless directories
6 | .serverless
--------------------------------------------------------------------------------
/src/index.d.ts:
--------------------------------------------------------------------------------
1 | declare module "*.json" {
2 | const value: any;
3 | export default value;
4 | }
5 |
6 | declare module require {}
--------------------------------------------------------------------------------
/src/api/handler.ts:
--------------------------------------------------------------------------------
1 | import getKittyRecommendations from './kitty/getKittyRecommendations';
2 | module.exports.getKittyRecommendations = getKittyRecommendations;
3 |
--------------------------------------------------------------------------------
/src/api/events/basic.json:
--------------------------------------------------------------------------------
1 | {
2 | "method": "GET",
3 | "headers": {
4 | "host": "localhost:8000",
5 | "user-agent": "curl/7.49.1",
6 | "accept": "*/*"
7 | },
8 | "body": {},
9 | "path": {},
10 | "query": {
11 | "foo": "bar"
12 | }
13 | }
--------------------------------------------------------------------------------
/src/index.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import * as ReactDOM from 'react-dom';
3 | import { HashRouter } from 'react-router-dom';
4 | import { App } from './App';
5 | ReactDOM.render(
6 |
7 |
8 | ,
9 | document.getElementById('app')
10 | );
11 |
--------------------------------------------------------------------------------
/tslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "defaultSeverity": "warning",
3 | "extends": [
4 | "tslint:recommended",
5 | "tslint-react"
6 | ],
7 | "jsRules": {},
8 | "rules": {
9 | "trailing-comma": false,
10 | "quotemark": [true, "single", "avoid-escape", "avoid-template"],
11 | "indent": [true, "tabs", 2]
12 | },
13 | "rulesDirectory": []
14 | }
15 |
--------------------------------------------------------------------------------
/src/api/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "api",
3 | "version": "1.0.0",
4 | "main": "index.js",
5 | "author": "Abhishek Chadha",
6 | "license": "MIT",
7 | "devDependencies": {
8 | "serverless": "^1.24.1",
9 | "serverless-plugin-typescript": "^1.1.3"
10 | },
11 | "dependencies": {
12 | "cryptokitties-contrib": "^0.1.0",
13 | "jsdom": "^11.5.1",
14 | "lodash": "^4.17.4",
15 | "node-fetch": "^1.7.3"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/utils.ts:
--------------------------------------------------------------------------------
1 | import * as _ from 'lodash';
2 | export const isNull = (v: any) => v === undefined || v === null;
3 | export const isNonNull = (v: any) => !isNull(v);
4 | export const randomEnumValue = (v: any) => {
5 | const keys = Object.keys({...v});
6 | const randInt = _.random(0, keys.length - 1);
7 | return v[keys[randInt]];
8 | };
9 |
10 | export const randomKey = (v: any) => {
11 | const keys = Object.keys({...v});
12 | const randInt = _.random(0, keys.length - 1);
13 | return keys[randInt];
14 | };
15 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "allowJs": true,
4 | "outDir": "./dist/",
5 | "sourceMap": true,
6 | "noImplicitAny": false,
7 | "allowSyntheticDefaultImports": true,
8 | "module": "commonjs",
9 | "target": "es5",
10 | "jsx": "react",
11 | "lib": ["es2015", "dom"],
12 | "types": [
13 | "jest"
14 | ],
15 | "externals": {
16 | "react": "React",
17 | "react-dom": "ReactDOM"
18 | }
19 | },
20 | "include": [
21 | "./src/**/*"
22 | ]
23 | }
--------------------------------------------------------------------------------
/src/__tests__/App.test.tsx:
--------------------------------------------------------------------------------
1 | /**
2 | * Basic render test
3 | */
4 |
5 | import * as React from 'react';
6 | import * as ShallowRenderer from 'react-test-renderer/shallow';
7 | import { App } from '../App';
8 |
9 | let renderer: ShallowRenderer.ShallowRenderer;
10 |
11 | beforeAll(() => {
12 | renderer = ShallowRenderer.createRenderer();
13 | });
14 |
15 | describe('Client basics', () => {
16 | it('App should render', () => {
17 | renderer.render(, null);
18 | const result: {} = renderer.getRenderOutput();
19 | expect(result).toBeTruthy();
20 | expect.assertions(1);
21 | });
22 | });
23 |
--------------------------------------------------------------------------------
/src/components/Genes.ts:
--------------------------------------------------------------------------------
1 | // tslint:disable:forin
2 | import { BodyType, EyeType, MouthType, PatternType } from './Cryptokitty';
3 | let map = null;
4 | let initialized = false;
5 | export const Genes = async () => {
6 | if (initialized === true) {
7 | return map;
8 | }
9 | map = {};
10 | for (const b in BodyType) {
11 | for (const p in PatternType) {
12 | const svg = await fetch(`src/cattributes/body/${b}-${p}.svg`);
13 | map[`${b}-${p}`] = await svg.text();
14 | }
15 | }
16 |
17 | for (const et in EyeType) {
18 | const svg = await fetch(`src/cattributes/eye/${et}.svg`);
19 | map[`${et}`] = await svg.text();
20 | }
21 |
22 | for (const mt in MouthType) {
23 | const svg = await fetch(`src/cattributes/mouth/${mt}.svg`);
24 | map[`${mt}`] = await svg.text();
25 | }
26 | initialized = true;
27 | return map;
28 | };
29 |
--------------------------------------------------------------------------------
/src/cattributes/colors.ts:
--------------------------------------------------------------------------------
1 | export const Primary = {
2 | mauveover: '#ded0ee',
3 | cloudwhite: '#ffffff',
4 | salmon: '#f4a792',
5 | shadowgrey: '#b1b1be',
6 | orangesoda: '#f7bc56',
7 | aquamarine: '#add5d2',
8 | greymatter: '#d1dadf',
9 | oldlace: '#ffebe9',
10 | cottoncandy: '#ecd1eb'
11 | };
12 |
13 | export const Secondary = {
14 | peach: '#f9cfad',
15 | bloodred: '#ff7a7a',
16 | emeraldgreen: '#8be179',
17 | granitegrey: '#b1aeb9',
18 | kittencream: '#f7ebda',
19 | };
20 |
21 | export const Tertiary = {
22 | barkbrown: '#886662',
23 | cerulian: '#385877',
24 | scarlet: '#ea5f5a',
25 | skyblue: '#83d5ff',
26 | coffee: '#756650',
27 | royalpurple: '#cf5be8',
28 | lemonade: '#ffef85',
29 | swampgreen: '#44e192',
30 | chocolate: '#c47e33',
31 | royalblue: '#5b6ee8',
32 | wolfgrey: '#737184'
33 | };
34 |
35 | export const EyeColor = {
36 | gold: '#fcdf35',
37 | bubblegum: '#ef52d1',
38 | limegreen: '#aef72f',
39 | chestnut: '#a56429',
40 | topaz: '#0ba09c',
41 | mintgreen: '#43edac',
42 | strawberry: '#ef4b62',
43 | sizzurp: '#7c40ff',
44 | };
45 |
--------------------------------------------------------------------------------
/src/App.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { Route } from 'react-router-dom';
3 | import { Grid, Input, Label, Menu } from 'semantic-ui-react';
4 | import { Container } from 'semantic-ui-react';
5 | import { About } from './components/About';
6 |
7 | // tslint:disable-next-line:no-var-requires
8 | export class App extends React.Component<{}, {}> {
9 |
10 | public constructor(props) {
11 | super(props);
12 | }
13 |
14 | public render() {
15 | return (
16 |
17 |
18 |
19 |
20 |
21 | CryptoKitty Designer
22 |
Make the kitty of your dreams
23 |
24 | Kittens and ETH appreciated @
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 | );
37 | }
38 | }
39 |
40 | const style = {
41 | };
42 |
--------------------------------------------------------------------------------
/src/cattributes/eye/googly.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | entry: "./src/index.tsx",
3 | output: {
4 | filename: "bundle.js",
5 | path: __dirname + "/dist"
6 | },
7 |
8 | // Enable sourcemaps for debugging webpack's output.
9 | devtool: "source-map",
10 |
11 | resolve: {
12 | // Add '.ts' and '.tsx' as resolvable extensions.
13 | extensions: [".ts", ".tsx", ".js", ".json"]
14 | },
15 |
16 | module: {
17 | rules: [
18 | // All files with a '.ts' or '.tsx' extension will be handled by 'awesome-typescript-loader'.
19 | { test: /\.tsx?$/, loader: "awesome-typescript-loader" },
20 |
21 | // All output '.js' files will have any sourcemaps re-processed by 'source-map-loader'.
22 | { enforce: "pre", test: /\.js$/, loader: "source-map-loader" },
23 |
24 | // All css files will go through the webpack css-loader
25 | { test: /\.css$/, use: [ 'style-loader', 'css-loader' ] }
26 | ]
27 | },
28 |
29 | // When importing a module whose path matches one of the following, just
30 | // assume a corresponding global variable exists and use that instead.
31 | // This is important because it allows us to avoid bundling all of our
32 | // dependencies, which allows browsers to cache those libraries between builds.
33 | externals: {
34 | "react": "React",
35 | "react-dom": "ReactDOM",
36 | "firebase": "firebase"
37 | },
38 | };
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
13 | CryptoKitty and Me
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | Star
24 |
25 |
26 |
27 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "cryptokitty-designer",
3 | "version": "1.0.0",
4 | "description": "Build designer cryptokitties",
5 | "main": "index.js",
6 | "author": "Abhishek Chadha",
7 | "license": "MIT",
8 | "private": true,
9 | "scripts": {
10 | "start": "webpack-dev-server",
11 | "build": "webpack"
12 | },
13 | "dependencies": {
14 | "cryptokitties-contrib": "^0.1.0",
15 | "jest": "^21.2.1",
16 | "jsdom": "^11.5.1",
17 | "lodash": "^4.17.4",
18 | "node-fetch": "^1.7.3",
19 | "puppeteer": "^0.13.0",
20 | "react": "^16.0.0",
21 | "react-dom": "^16.0.0",
22 | "react-router-dom": "^4.2.2",
23 | "semantic-ui-react": "^0.75.1"
24 | },
25 | "devDependencies": {
26 | "@types/jest": "^21.1.6",
27 | "@types/react": "^16.0.19",
28 | "@types/react-dom": "^16.0.2",
29 | "@types/react-router-dom": "^4.2.0",
30 | "@types/react-test-renderer": "^16.0.0",
31 | "awesome-typescript-loader": "^3.2.3",
32 | "css-loader": "^0.28.7",
33 | "react-test-renderer": "^16.1.1",
34 | "serverless-offline": "^3.16.0",
35 | "serverless-plugin-typescript": "^1.1.3",
36 | "serverless-webpack": "^4.1.0",
37 | "source-map-loader": "^0.2.3",
38 | "style-loader": "^0.19.0",
39 | "ts-jest": "^21.2.2",
40 | "ts-loader": "^3.2.0",
41 | "tslint": "^5.8.0",
42 | "tslint-react": "^3.2.0",
43 | "tslint-react-recommended": "^1.0.15",
44 | "typescript": "^2.5.3",
45 | "webpack": "^3.8.1",
46 | "webpack-dev-server": "^2.9.3"
47 | },
48 | "jest": {
49 | "transform": {
50 | ".(ts|tsx)": "/node_modules/ts-jest/preprocessor.js"
51 | },
52 | "testRegex": "(/__tests__/.*|\\.(test|spec))\\.(ts|tsx|js)$",
53 | "moduleFileExtensions": [
54 | "ts",
55 | "tsx",
56 | "js",
57 | "json"
58 | ]
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/cattributes/eye/fabulous.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/cattributes/eye/simple.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/api/kitty/getKittyRecommendations.ts:
--------------------------------------------------------------------------------
1 | import * as ck from 'cryptokitties-contrib';
2 | import { JSDOM } from 'jsdom';
3 | import * as _ from 'lodash';
4 | import * as fetch from 'node-fetch';
5 |
6 | export default async function(event, context, callback) {
7 | const matron = event.queryStringParameters.matron;
8 | const sire = event.queryStringParameters.sire;
9 | const result = await kittyRecommendation(matron, [sire]);
10 | const response = {
11 | body: JSON.stringify({
12 | input: { matron, sire },
13 | result,
14 | }),
15 | statusCode: 200,
16 | };
17 | callback(null, response);
18 | }
19 |
20 | async function kittyRecommendation(owned, kittys) {
21 | const kittenPrices = [];
22 | for (const kitty of kittys) {
23 | const result = await expectedPriceOfKittens(owned, kitty);
24 | kittenPrices.push({ ...result, id: kitty });
25 | }
26 | const sorted = _.sortBy(kittenPrices, 'averagePriceOfKitten');
27 | return sorted;
28 | }
29 |
30 | async function getKittyGenomePrediction(kitty1, kitty2) {
31 | if (typeof kitty1 !== 'string') { kitty1 = String(kitty1); }
32 | if (typeof kitty2 !== 'string') { kitty2 = String(kitty2); }
33 | const kittyGenomeServiceUrl = 'http://www.kitty.services/api';
34 | const res = await fetch(`${kittyGenomeServiceUrl}/gene`, {
35 | body: JSON.stringify( [kitty1, kitty2]),
36 | headers: {
37 | 'Accept': 'application/json',
38 | 'Content-Type': 'application/json;charset=UTF-8',
39 | 'Origin': 'http://www.kitty.services',
40 | },
41 | method: 'POST',
42 | });
43 | return res.json();
44 | }
45 |
46 | async function kittiesOnAuction() {
47 | return _.map((await ck.listAuctions()), (k) => k.id)
48 | }
49 |
50 | async function getCattributes() {
51 | const kittyGenePriceIndex = `https://cryptokittydex.com/cattributes`;
52 | const res = await fetch(`${kittyGenePriceIndex}`);
53 | const html = await res.text();
54 | const dom = new JSDOM(html);
55 | const cattributeInfo = dom.window.document.querySelectorAll('.cattribute-info-layer');
56 | const result = {};
57 | _.map(cattributeInfo, (c) => {
58 | result[c.querySelector('strong').innerHTML] = {
59 | population: parseInt(c.innerHTML.split('\n')[2].replace('kitties', '').replace(/,/g, '').trim(), 10),
60 | price: parseFloat(c.querySelector('span[data-title="Average price paid for a kitty possessing this cattribute"]')
61 | .innerHTML.replace('~', '').replace('ETH', '').trim()),
62 | };
63 | });
64 | return result;
65 | }
66 |
67 | async function expectedPriceOfKittens(kitty1, kitty2) {
68 | const cattributeProbabilities = await getKittyGenomePrediction(kitty1, kitty2);
69 | const cattributes = await getCattributes();
70 | const fancyPrice = 2;
71 | const cattributeProbsSum = _.reduce(cattributeProbabilities.results, (a, c) => a + c[1], 0);
72 | const normalizedCattributeProbs = _.map(cattributeProbabilities.results, (c) => [ c[0], c[1] / cattributeProbsSum]);
73 | let avgPriceOfKitten = 0;
74 | // tslint:disable-next-line:prefer-for-of
75 | for (let i = 0; i < normalizedCattributeProbs.length; i++) {
76 | if (normalizedCattributeProbs[i][0] !== 'fancy') {
77 | avgPriceOfKitten =
78 | avgPriceOfKitten + cattributes[normalizedCattributeProbs[i][0]].price * normalizedCattributeProbs[i][1];
79 | }
80 | }
81 | return {
82 | averagePriceOfKitten: avgPriceOfKitten,
83 | results: cattributeProbabilities.results
84 | };
85 | }
86 |
--------------------------------------------------------------------------------
/src/cattributes/eye/raisedbrow.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/api/serverless.yml:
--------------------------------------------------------------------------------
1 | # Welcome to Serverless!
2 | #
3 | # This file is the main config file for your service.
4 | # It's very minimal at this point and uses default values.
5 | # You can always add more config options for more control.
6 | # We've included some commented out config examples here.
7 | # Just uncomment any of them to get that config option.
8 | #
9 | # For full config options, check the docs:
10 | # docs.serverless.com
11 | #
12 | # Happy Coding!
13 |
14 | service: cryptokittyandme
15 |
16 | # You can pin your service to only deploy with a specific Serverless version
17 | # Check out our docs for more details
18 | # frameworkVersion: "=X.X.X"
19 | plugins:
20 | - serverless-plugin-typescript
21 | - serverless-offline
22 | provider:
23 | name: aws
24 | runtime: nodejs6.10
25 |
26 | functions:
27 | getKittyRecommendations:
28 | handler: handler.getKittyRecommendations
29 | events:
30 | - http:
31 | path: getKittyRecommendations
32 | method: get
33 |
34 |
35 | # you can overwrite defaults here
36 | # stage: dev
37 | # region: us-east-1
38 |
39 | # you can add statements to the Lambda function's IAM Role here
40 | # iamRoleStatements:
41 | # - Effect: "Allow"
42 | # Action:
43 | # - "s3:ListBucket"
44 | # Resource: { "Fn::Join" : ["", ["arn:aws:s3:::", { "Ref" : "ServerlessDeploymentBucket" } ] ] }
45 | # - Effect: "Allow"
46 | # Action:
47 | # - "s3:PutObject"
48 | # Resource:
49 | # Fn::Join:
50 | # - ""
51 | # - - "arn:aws:s3:::"
52 | # - "Ref" : "ServerlessDeploymentBucket"
53 | # - "/*"
54 |
55 | # you can define service wide environment variables here
56 | # environment:
57 | # variable1: value1
58 |
59 | # you can add packaging information here
60 | #package:
61 | # include:
62 | # - include-me.js
63 | # - include-me-dir/**
64 | # exclude:
65 | # - exclude-me.js
66 | # - exclude-me-dir/**
67 |
68 |
69 | # The following are a few example events you can configure
70 | # NOTE: Please make sure to change your handler code to work with those events
71 | # Check the event documentation for details
72 | # events:
73 | # - http:
74 | # path: users/create
75 | # method: get
76 | # - s3: ${env:BUCKET}
77 | # - schedule: rate(10 minutes)
78 | # - sns: greeter-topic
79 | # - stream: arn:aws:dynamodb:region:XXXXXX:table/foo/stream/1970-01-01T00:00:00.000
80 | # - alexaSkill
81 | # - alexaSmartHome: amzn1.ask.skill.xx-xx-xx-xx
82 | # - iot:
83 | # sql: "SELECT * FROM 'some_topic'"
84 | # - cloudwatchEvent:
85 | # event:
86 | # source:
87 | # - "aws.ec2"
88 | # detail-type:
89 | # - "EC2 Instance State-change Notification"
90 | # detail:
91 | # state:
92 | # - pending
93 | # - cloudwatchLog: '/aws/lambda/hello'
94 | # - cognitoUserPool:
95 | # pool: MyUserPool
96 | # trigger: PreSignUp
97 |
98 | # Define function environment variables here
99 | # environment:
100 | # variable2: value2
101 |
102 | # you can add CloudFormation resource templates here
103 | #resources:
104 | # Resources:
105 | # NewResource:
106 | # Type: AWS::S3::Bucket
107 | # Properties:
108 | # BucketName: my-new-bucket
109 | # Outputs:
110 | # NewOutput:
111 | # Description: "Description for the output"
112 | # Value: "Some output value"
113 |
--------------------------------------------------------------------------------
/src/cattributes/eye/crazy.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/cattributes/eye/thicccbrowz.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/cattributes/eye/otaku.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/cattributes/eye/wingtips.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/components/Cryptokitty.tsx:
--------------------------------------------------------------------------------
1 | import * as _ from 'lodash';
2 | import * as React from 'react';
3 | import { Link } from 'react-router-dom';
4 | import { Button, Container, Divider, Grid, Header, Segment } from 'semantic-ui-react';
5 | import * as c from '../cattributes/colors';
6 | import { isNonNull, randomEnumValue } from '../utils';
7 | import { Genes } from './Genes';
8 |
9 | interface ICryptokittyFeatures {
10 | colors?: string[];
11 | body?: BodyType;
12 | pattern?: PatternType;
13 | mouth?: MouthType;
14 | eye?: EyeType;
15 | isSpecial?: boolean;
16 | }
17 |
18 | export enum BodyType {
19 | mainecoon = 'mainecoon',
20 | cymric = 'cymric',
21 | laperm = 'laperm',
22 | munchkin = 'munchkin',
23 | sphynx = 'sphynx',
24 | ragamuffin = 'ragamuffin',
25 | himalayan = 'himalayan',
26 | chartreux = 'chartreux',
27 | }
28 |
29 | export enum PatternType {
30 | spock = 'spock',
31 | tigerpunk = 'tigerpunk',
32 | calicool = 'calicool',
33 | luckystripe = 'luckystripe',
34 | jaguar = 'jaguar',
35 | totesbasic = 'totesbasic',
36 | }
37 |
38 | export enum MouthType {
39 | whixtensions = 'whixtensions',
40 | dali = 'dali',
41 | saycheese = 'saycheese',
42 | beard = 'beard',
43 | tongue = 'tongue',
44 | happygokitty = 'happygokitty',
45 | pouty = 'pouty',
46 | soserious = 'soserious',
47 | gerbil = 'gerbil'
48 | }
49 |
50 | export enum EyeType {
51 | wingtips = 'wingtips',
52 | fabulous = 'fabulous',
53 | otaku = 'otaku',
54 | raisedbrow = 'raisedbrow',
55 | simple = 'simple',
56 | crazy = 'crazy',
57 | thicccbrowz = 'thicccbrowz',
58 | googly = 'googly',
59 | }
60 |
61 | interface ICryptokittyState {
62 | kittyImage?: string;
63 | kittyMouth?: string;
64 | kittyEye?: string;
65 | genes?: string;
66 | }
67 |
68 | export class Cryptokitty extends React.Component {
69 | static private cache = {};
70 | constructor(props) {
71 | super(props);
72 | this.state = {};
73 | const body = props.body;
74 | const pattern = props.pattern;
75 | const mouth = props.mouth;
76 | const eye = props.eye;
77 |
78 | const colors = props.colors;
79 | this.detectKittyColors = this.detectKittyColors.bind(this);
80 | this.render = this.render.bind(this);
81 | }
82 |
83 | public async componentWillMount() {
84 | const { body, pattern, mouth, eye } = this.props;
85 | const colors = this.props.colors || [
86 | c.Primary.shadowgrey, c.Secondary.kittencream, c.Tertiary.royalpurple, c.EyeColor.bubblegum
87 | ];
88 | const genes = await Genes();
89 | this.setState({ genes });
90 | }
91 |
92 | public async componentDidReceiveProps() {
93 | const { body, pattern, mouth, eye } = this.props;
94 | const colors = this.props.colors || [
95 | c.Primary.shadowgrey, c.Secondary.kittencream, c.Tertiary.royalpurple, c.EyeColor.bubblegum
96 | ];
97 | }
98 |
99 | public detectKittyColors(svgText) {
100 | const colors = [null, null, null, null];
101 | for (const color in c.Primary) {
102 | if (svgText.indexOf(c.Primary[color]) > -1) {
103 | colors[0] = color;
104 | }
105 | }
106 | for (const color in c.Secondary) {
107 | if (svgText.indexOf(c.Secondary[color]) > -1) {
108 | colors[1] = color;
109 | }
110 | }
111 | for (const color in c.Tertiary) {
112 | if (svgText.indexOf(c.Tertiary[color]) > -1) {
113 | colors[2] = color;
114 | }
115 | }
116 |
117 | for (const color in c.EyeColor) {
118 | if (svgText.indexOf(c.EyeColor[color]) > -1) {
119 | colors[3] = color;
120 | }
121 | }
122 |
123 | return colors;
124 | }
125 |
126 | public render() {
127 | const genes = this.state.genes;
128 | if (genes === undefined) {
129 | return
;
130 | }
131 | const { body, pattern, mouth, eye, colors } = this.props;
132 |
133 | let kittyImage = genes[`${this.props.body}-${this.props.pattern}`];
134 | let kittyMouth = genes[this.props.mouth];
135 | let kittyEye = genes[this.props.eye];
136 |
137 | const bodyColors = this.detectKittyColors(kittyImage);
138 | const eyeColors = this.detectKittyColors(kittyEye);
139 | const mouthColors = this.detectKittyColors(kittyMouth);
140 |
141 | if (isNonNull(bodyColors[0])) {
142 | kittyImage = kittyImage.replace(new RegExp(c.Primary[bodyColors[0]], "g"), colors[0]);
143 | }
144 |
145 | if (isNonNull(bodyColors[1])) {
146 | kittyImage = kittyImage.replace(new RegExp(c.Secondary[bodyColors[1]], "g"), colors[1]);
147 | }
148 |
149 | if (isNonNull(eyeColors[3])) {
150 | kittyEye = kittyEye.replace(new RegExp(c.EyeColor[eyeColors[3]], "g"), colors[3]);
151 | }
152 |
153 | if (isNonNull(bodyColors[2])) {
154 | kittyImage = kittyImage.replace(new RegExp(c.Tertiary[bodyColors[2]], "g"), colors[2]);
155 | }
156 |
157 | if (isNonNull(mouthColors[0])) {
158 | kittyMouth = kittyMouth.replace(new RegExp(c.Primary[mouthColors[0]], "g"), colors[0]);
159 | }
160 | // tslint:disable:jsx-no-multiline-js
161 |
162 | return (
163 |
164 | {
165 | (kittyImage === null || kittyMouth === null || kittyEye === null ?
166 |
167 |

168 |
:
169 | )
174 | }
175 |
176 | );
177 | }
178 | }
179 |
180 | const styles: React.CSSProperties = {
181 | fixed: { position: 'absolute', top: 0, left: 0, height: "300px", width: "300px" }
182 | };
183 |
--------------------------------------------------------------------------------
/src/cattributes/mouth/soserious.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/cattributes/mouth/gerbil.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/cattributes/mouth/happygokitty.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/components/About.tsx:
--------------------------------------------------------------------------------
1 | // tslint:disable:jsx-no-multiline-js
2 | import * as React from 'react';
3 | import { Link } from 'react-router-dom';
4 |
5 | import { Button, Container, Divider, Grid, Header, Input, Segment } from 'semantic-ui-react';
6 | import { BodyType, Cryptokitty, EyeType, MouthType, PatternType } from './Cryptokitty';
7 |
8 | import * as c from '../cattributes/colors';
9 | import { randomEnumValue, randomKey } from '../utils';
10 |
11 | import * as _ from 'lodash';
12 | export class About extends React.Component {
13 |
14 | constructor(props) {
15 | super(props);
16 | this.fieldChanged = this.fieldChanged.bind(this);
17 | this.randomKitty = this.randomKitty.bind(this);
18 | this.findKitty = this.randomKitty.bind(this);
19 | }
20 |
21 | // tslint:disable-next-line:member-ordering
22 | public state = {
23 | body: randomEnumValue(BodyType),
24 | eye: randomEnumValue(EyeType),
25 | eyeColor: randomKey(c.EyeColor),
26 | mouth: randomEnumValue(MouthType),
27 | pattern: randomEnumValue(PatternType),
28 | primary: randomKey(c.Primary),
29 | secondary: randomKey(c.Secondary),
30 | tertiary: randomKey(c.Tertiary),
31 | };
32 |
33 | public fieldChanged(e) {
34 | this.setState({
35 | ...this.state,
36 | [e.target.name]: e.target.value
37 | });
38 | }
39 |
40 | public randomKitty() {
41 | this.setState({
42 | body: randomEnumValue(BodyType),
43 | eye: randomEnumValue(EyeType),
44 | eyeColor: randomKey(c.EyeColor)
45 | mouth: randomEnumValue(MouthType),
46 | pattern: randomEnumValue(PatternType),
47 | primary: randomKey(c.Primary),
48 | secondary: randomKey(c.Secondary),
49 | tertiary: randomKey(c.Tertiary),
50 | });
51 | }
52 |
53 | public render() {
54 | const onFieldChange = this.fieldChanged;
55 | const randomKitty = this.randomKitty;
56 | const findKitty = this.findKitty;
57 | const { body, pattern, eye, mouth, primary, secondary, tertiary, eyeColor } = this.state;
58 | const searchUrlStr = [body, pattern, eye, mouth, primary, secondary].join('%20');
59 | const kittyFindUrl = `https://www.cryptokitties.co/marketplace/sale?search=${searchUrlStr}`;
60 | const openKittyUrl = () => {
61 | window.open(kittyFindUrl, '_blank');
62 | };
63 | return (
64 |
65 |
66 |
67 |
68 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 | {
87 | _.map(Object.keys(BodyType), (k) => (
88 |
89 |
90 |
91 |
92 |
93 |
94 | ))
95 | }
96 |
97 |
98 |
99 |
100 | {
101 | _.map(Object.keys(PatternType), (k) => (
102 |
103 |
104 |
105 |
106 |
107 |
108 | ))
109 | }
110 |
111 |
112 |
113 |
114 | {
115 | _.map(Object.keys(EyeType), (k) => (
116 |
117 |
118 |
119 |
120 |
121 |
122 | ))
123 | }
124 |
125 |
126 |
127 | {
128 | _.map(Object.keys(MouthType), (k) => (
129 |
130 |
131 |
132 |
133 |
134 |
135 | ))
136 | }
137 |
138 |
139 |
140 | {
141 | _.map(Object.keys(c.Primary), (k) => (
142 |
143 |
144 |
145 |
146 |
147 |
148 | ))
149 | }
150 |
151 |
152 |
153 | {
154 | _.map(Object.keys(c.Secondary), (k) => (
155 |
156 |
157 |
158 |
159 |
160 |
161 | ))
162 | }
163 |
164 |
165 |
166 | {
167 | _.map(Object.keys(c.Tertiary), (k) => (
168 |
169 |
170 |
171 |
172 |
173 |
174 | ))
175 | }
176 |
177 |
178 |
179 | {
180 | _.map(Object.keys(c.EyeColor), (k) => (
181 |
182 |
183 |
184 |
185 |
186 |
187 | ))
188 | }
189 |
190 |
191 |
192 |
193 |
194 | );
195 | }
196 | }
197 |
198 | const style = {
199 | };
200 |
--------------------------------------------------------------------------------
/src/cattributes/mouth/whixtensions.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/cattributes/mouth/saycheese.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/cattributes/mouth/pouty.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/cattributes/mouth/tongue.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/cattributes/mouth/dali.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/cattributes/mouth/beard.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/cattributes/body/laperm-totesbasic.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/cattributes/body/laperm-spock.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/cattributes/body/laperm-calicool.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/cattributes/body/munchkin-totesbasic.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------