Migrate all the things

* Migrates from Mongo to Postgres.
* Migrates from JSPM to Webpack.
* Migrates from React to Vuejs.
* Migrates from Bootstrap to Bulma.

Also:
* Fixes rendering of meta data in the document head tag.
This commit is contained in:
Jonathan Cremin 2016-10-03 13:31:29 +01:00
parent 09706778d9
commit 7bb0497ff4
76 changed files with 6741 additions and 1760 deletions

View file

Before

Width:  |  Height:  |  Size: 7.2 KiB

After

Width:  |  Height:  |  Size: 7.2 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 7.9 KiB

After

Width:  |  Height:  |  Size: 7.9 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 979 B

After

Width:  |  Height:  |  Size: 979 B

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 644 B

After

Width:  |  Height:  |  Size: 644 B

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 770 B

After

Width:  |  Height:  |  Size: 770 B

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 5 KiB

After

Width:  |  Height:  |  Size: 5 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 2 KiB

After

Width:  |  Height:  |  Size: 2 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 7.8 KiB

After

Width:  |  Height:  |  Size: 7.8 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 6.1 KiB

After

Width:  |  Height:  |  Size: 6.1 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 951 B

After

Width:  |  Height:  |  Size: 951 B

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 7.7 KiB

After

Width:  |  Height:  |  Size: 7.7 KiB

Before After
Before After

View file

@ -1,568 +0,0 @@
System.config({
baseURL: "/",
defaultJSExtensions: true,
transpiler: "babel",
babelOptions: {
"optional": [
"runtime",
"optimisation.modules.system"
]
},
paths: {
"github:*": "jspm_packages/github/*",
"npm:*": "jspm_packages/npm/*"
},
map: {
"babel": "npm:babel-core@5.8.34",
"babel-runtime": "npm:babel-runtime@5.8.34",
"core-js": "npm:core-js@1.2.6",
"history": "npm:history@1.17.0",
"react": "npm:react@0.14.6",
"react-dom": "npm:react-dom@0.14.6",
"react-google-analytics": "npm:react-google-analytics@0.2.0",
"react-router": "npm:react-router@1.0.3",
"superagent": "npm:superagent@1.2.0",
"github:jspm/nodelibs-assert@0.1.0": {
"assert": "npm:assert@1.3.0"
},
"github:jspm/nodelibs-buffer@0.1.0": {
"buffer": "npm:buffer@3.6.0"
},
"github:jspm/nodelibs-constants@0.1.0": {
"constants-browserify": "npm:constants-browserify@0.0.1"
},
"github:jspm/nodelibs-crypto@0.1.0": {
"crypto-browserify": "npm:crypto-browserify@3.11.0"
},
"github:jspm/nodelibs-domain@0.1.0": {
"domain-browser": "npm:domain-browser@1.1.7"
},
"github:jspm/nodelibs-events@0.1.1": {
"events": "npm:events@1.0.2"
},
"github:jspm/nodelibs-http@1.7.1": {
"Base64": "npm:Base64@0.2.1",
"events": "github:jspm/nodelibs-events@0.1.1",
"inherits": "npm:inherits@2.0.1",
"stream": "github:jspm/nodelibs-stream@0.1.0",
"url": "github:jspm/nodelibs-url@0.1.0",
"util": "github:jspm/nodelibs-util@0.1.0"
},
"github:jspm/nodelibs-https@0.1.0": {
"https-browserify": "npm:https-browserify@0.0.0"
},
"github:jspm/nodelibs-net@0.1.2": {
"buffer": "github:jspm/nodelibs-buffer@0.1.0",
"crypto": "github:jspm/nodelibs-crypto@0.1.0",
"http": "github:jspm/nodelibs-http@1.7.1",
"net": "github:jspm/nodelibs-net@0.1.2",
"process": "github:jspm/nodelibs-process@0.1.2",
"stream": "github:jspm/nodelibs-stream@0.1.0",
"timers": "github:jspm/nodelibs-timers@0.1.0",
"util": "github:jspm/nodelibs-util@0.1.0"
},
"github:jspm/nodelibs-os@0.1.0": {
"os-browserify": "npm:os-browserify@0.1.2"
},
"github:jspm/nodelibs-path@0.1.0": {
"path-browserify": "npm:path-browserify@0.0.0"
},
"github:jspm/nodelibs-process@0.1.2": {
"process": "npm:process@0.11.2"
},
"github:jspm/nodelibs-querystring@0.1.0": {
"querystring": "npm:querystring@0.2.0"
},
"github:jspm/nodelibs-stream@0.1.0": {
"stream-browserify": "npm:stream-browserify@1.0.0"
},
"github:jspm/nodelibs-string_decoder@0.1.0": {
"string_decoder": "npm:string_decoder@0.10.31"
},
"github:jspm/nodelibs-timers@0.1.0": {
"timers-browserify": "npm:timers-browserify@1.4.2"
},
"github:jspm/nodelibs-tty@0.1.0": {
"tty-browserify": "npm:tty-browserify@0.0.0"
},
"github:jspm/nodelibs-url@0.1.0": {
"url": "npm:url@0.10.3"
},
"github:jspm/nodelibs-util@0.1.0": {
"util": "npm:util@0.10.3"
},
"github:jspm/nodelibs-vm@0.1.0": {
"vm-browserify": "npm:vm-browserify@0.0.4"
},
"github:jspm/nodelibs-zlib@0.1.0": {
"browserify-zlib": "npm:browserify-zlib@0.1.4"
},
"npm:amdefine@1.0.0": {
"fs": "github:jspm/nodelibs-fs@0.1.2",
"module": "github:jspm/nodelibs-module@0.1.0",
"path": "github:jspm/nodelibs-path@0.1.0",
"process": "github:jspm/nodelibs-process@0.1.2"
},
"npm:asap@2.0.3": {
"domain": "github:jspm/nodelibs-domain@0.1.0",
"process": "github:jspm/nodelibs-process@0.1.2"
},
"npm:asn1.js@4.3.0": {
"assert": "github:jspm/nodelibs-assert@0.1.0",
"bn.js": "npm:bn.js@4.6.2",
"buffer": "github:jspm/nodelibs-buffer@0.1.0",
"inherits": "npm:inherits@2.0.1",
"minimalistic-assert": "npm:minimalistic-assert@1.0.0",
"vm": "github:jspm/nodelibs-vm@0.1.0"
},
"npm:assert@1.3.0": {
"util": "npm:util@0.10.3"
},
"npm:async@0.9.2": {
"process": "github:jspm/nodelibs-process@0.1.2",
"systemjs-json": "github:systemjs/plugin-json@0.1.0"
},
"npm:babel-runtime@5.8.34": {
"process": "github:jspm/nodelibs-process@0.1.2"
},
"npm:browserify-aes@1.0.5": {
"buffer": "github:jspm/nodelibs-buffer@0.1.0",
"buffer-xor": "npm:buffer-xor@1.0.3",
"cipher-base": "npm:cipher-base@1.0.2",
"create-hash": "npm:create-hash@1.1.2",
"crypto": "github:jspm/nodelibs-crypto@0.1.0",
"evp_bytestokey": "npm:evp_bytestokey@1.0.0",
"fs": "github:jspm/nodelibs-fs@0.1.2",
"inherits": "npm:inherits@2.0.1",
"systemjs-json": "github:systemjs/plugin-json@0.1.0"
},
"npm:browserify-cipher@1.0.0": {
"browserify-aes": "npm:browserify-aes@1.0.5",
"browserify-des": "npm:browserify-des@1.0.0",
"buffer": "github:jspm/nodelibs-buffer@0.1.0",
"crypto": "github:jspm/nodelibs-crypto@0.1.0",
"evp_bytestokey": "npm:evp_bytestokey@1.0.0"
},
"npm:browserify-des@1.0.0": {
"buffer": "github:jspm/nodelibs-buffer@0.1.0",
"cipher-base": "npm:cipher-base@1.0.2",
"crypto": "github:jspm/nodelibs-crypto@0.1.0",
"des.js": "npm:des.js@1.0.0",
"inherits": "npm:inherits@2.0.1"
},
"npm:browserify-rsa@4.0.0": {
"bn.js": "npm:bn.js@4.6.2",
"buffer": "github:jspm/nodelibs-buffer@0.1.0",
"constants": "github:jspm/nodelibs-constants@0.1.0",
"crypto": "github:jspm/nodelibs-crypto@0.1.0",
"randombytes": "npm:randombytes@2.0.1"
},
"npm:browserify-sign@4.0.0": {
"bn.js": "npm:bn.js@4.6.2",
"browserify-rsa": "npm:browserify-rsa@4.0.0",
"buffer": "github:jspm/nodelibs-buffer@0.1.0",
"create-hash": "npm:create-hash@1.1.2",
"create-hmac": "npm:create-hmac@1.1.4",
"crypto": "github:jspm/nodelibs-crypto@0.1.0",
"elliptic": "npm:elliptic@6.0.2",
"inherits": "npm:inherits@2.0.1",
"parse-asn1": "npm:parse-asn1@5.0.0",
"stream": "github:jspm/nodelibs-stream@0.1.0"
},
"npm:browserify-zlib@0.1.4": {
"assert": "github:jspm/nodelibs-assert@0.1.0",
"buffer": "github:jspm/nodelibs-buffer@0.1.0",
"pako": "npm:pako@0.2.8",
"process": "github:jspm/nodelibs-process@0.1.2",
"readable-stream": "npm:readable-stream@2.0.5",
"util": "github:jspm/nodelibs-util@0.1.0"
},
"npm:buffer-xor@1.0.3": {
"buffer": "github:jspm/nodelibs-buffer@0.1.0",
"systemjs-json": "github:systemjs/plugin-json@0.1.0"
},
"npm:buffer@3.6.0": {
"base64-js": "npm:base64-js@0.0.8",
"child_process": "github:jspm/nodelibs-child_process@0.1.0",
"fs": "github:jspm/nodelibs-fs@0.1.2",
"ieee754": "npm:ieee754@1.1.6",
"isarray": "npm:isarray@1.0.0",
"process": "github:jspm/nodelibs-process@0.1.2"
},
"npm:cipher-base@1.0.2": {
"buffer": "github:jspm/nodelibs-buffer@0.1.0",
"inherits": "npm:inherits@2.0.1",
"stream": "github:jspm/nodelibs-stream@0.1.0",
"string_decoder": "github:jspm/nodelibs-string_decoder@0.1.0"
},
"npm:combined-stream@0.0.7": {
"buffer": "github:jspm/nodelibs-buffer@0.1.0",
"delayed-stream": "npm:delayed-stream@0.0.5",
"stream": "github:jspm/nodelibs-stream@0.1.0",
"util": "github:jspm/nodelibs-util@0.1.0"
},
"npm:constants-browserify@0.0.1": {
"systemjs-json": "github:systemjs/plugin-json@0.1.0"
},
"npm:core-js@1.2.6": {
"fs": "github:jspm/nodelibs-fs@0.1.2",
"path": "github:jspm/nodelibs-path@0.1.0",
"process": "github:jspm/nodelibs-process@0.1.2",
"systemjs-json": "github:systemjs/plugin-json@0.1.0"
},
"npm:core-util-is@1.0.2": {
"buffer": "github:jspm/nodelibs-buffer@0.1.0"
},
"npm:create-ecdh@4.0.0": {
"bn.js": "npm:bn.js@4.6.2",
"buffer": "github:jspm/nodelibs-buffer@0.1.0",
"crypto": "github:jspm/nodelibs-crypto@0.1.0",
"elliptic": "npm:elliptic@6.0.2"
},
"npm:create-hash@1.1.2": {
"buffer": "github:jspm/nodelibs-buffer@0.1.0",
"cipher-base": "npm:cipher-base@1.0.2",
"crypto": "github:jspm/nodelibs-crypto@0.1.0",
"fs": "github:jspm/nodelibs-fs@0.1.2",
"inherits": "npm:inherits@2.0.1",
"ripemd160": "npm:ripemd160@1.0.1",
"sha.js": "npm:sha.js@2.4.4"
},
"npm:create-hmac@1.1.4": {
"buffer": "github:jspm/nodelibs-buffer@0.1.0",
"create-hash": "npm:create-hash@1.1.2",
"crypto": "github:jspm/nodelibs-crypto@0.1.0",
"inherits": "npm:inherits@2.0.1",
"stream": "github:jspm/nodelibs-stream@0.1.0"
},
"npm:crypto-browserify@3.11.0": {
"browserify-cipher": "npm:browserify-cipher@1.0.0",
"browserify-sign": "npm:browserify-sign@4.0.0",
"create-ecdh": "npm:create-ecdh@4.0.0",
"create-hash": "npm:create-hash@1.1.2",
"create-hmac": "npm:create-hmac@1.1.4",
"diffie-hellman": "npm:diffie-hellman@5.0.0",
"inherits": "npm:inherits@2.0.1",
"pbkdf2": "npm:pbkdf2@3.0.4",
"public-encrypt": "npm:public-encrypt@4.0.0",
"randombytes": "npm:randombytes@2.0.1"
},
"npm:debug@2.2.0": {
"fs": "github:jspm/nodelibs-fs@0.1.2",
"ms": "npm:ms@0.7.1",
"net": "github:jspm/nodelibs-net@0.1.2",
"process": "github:jspm/nodelibs-process@0.1.2",
"tty": "github:jspm/nodelibs-tty@0.1.0",
"util": "github:jspm/nodelibs-util@0.1.0"
},
"npm:delayed-stream@0.0.5": {
"stream": "github:jspm/nodelibs-stream@0.1.0",
"util": "github:jspm/nodelibs-util@0.1.0"
},
"npm:des.js@1.0.0": {
"buffer": "github:jspm/nodelibs-buffer@0.1.0",
"inherits": "npm:inherits@2.0.1",
"minimalistic-assert": "npm:minimalistic-assert@1.0.0"
},
"npm:diffie-hellman@5.0.0": {
"bn.js": "npm:bn.js@4.6.2",
"buffer": "github:jspm/nodelibs-buffer@0.1.0",
"crypto": "github:jspm/nodelibs-crypto@0.1.0",
"miller-rabin": "npm:miller-rabin@4.0.0",
"randombytes": "npm:randombytes@2.0.1",
"systemjs-json": "github:systemjs/plugin-json@0.1.0"
},
"npm:domain-browser@1.1.7": {
"events": "github:jspm/nodelibs-events@0.1.1"
},
"npm:elliptic@6.0.2": {
"bn.js": "npm:bn.js@4.6.2",
"brorand": "npm:brorand@1.0.5",
"hash.js": "npm:hash.js@1.0.3",
"inherits": "npm:inherits@2.0.1",
"systemjs-json": "github:systemjs/plugin-json@0.1.0"
},
"npm:envify@3.4.0": {
"jstransform": "npm:jstransform@10.1.0",
"process": "github:jspm/nodelibs-process@0.1.2",
"through": "npm:through@2.3.8"
},
"npm:esprima-fb@13001.1001.0-dev-harmony-fb": {
"fs": "github:jspm/nodelibs-fs@0.1.2",
"process": "github:jspm/nodelibs-process@0.1.2"
},
"npm:evp_bytestokey@1.0.0": {
"buffer": "github:jspm/nodelibs-buffer@0.1.0",
"create-hash": "npm:create-hash@1.1.2",
"crypto": "github:jspm/nodelibs-crypto@0.1.0"
},
"npm:fbjs@0.6.1": {
"core-js": "npm:core-js@1.2.6",
"loose-envify": "npm:loose-envify@1.1.0",
"process": "github:jspm/nodelibs-process@0.1.2",
"promise": "npm:promise@7.1.1",
"ua-parser-js": "npm:ua-parser-js@0.7.10",
"whatwg-fetch": "npm:whatwg-fetch@0.9.0"
},
"npm:form-data@0.2.0": {
"async": "npm:async@0.9.2",
"buffer": "github:jspm/nodelibs-buffer@0.1.0",
"combined-stream": "npm:combined-stream@0.0.7",
"fs": "github:jspm/nodelibs-fs@0.1.2",
"http": "github:jspm/nodelibs-http@1.7.1",
"https": "github:jspm/nodelibs-https@0.1.0",
"mime-types": "npm:mime-types@2.0.14",
"path": "github:jspm/nodelibs-path@0.1.0",
"process": "github:jspm/nodelibs-process@0.1.2",
"url": "github:jspm/nodelibs-url@0.1.0",
"util": "github:jspm/nodelibs-util@0.1.0"
},
"npm:formidable@1.0.14": {
"assert": "github:jspm/nodelibs-assert@0.1.0",
"buffer": "github:jspm/nodelibs-buffer@0.1.0",
"crypto": "github:jspm/nodelibs-crypto@0.1.0",
"events": "github:jspm/nodelibs-events@0.1.1",
"fs": "github:jspm/nodelibs-fs@0.1.2",
"http": "github:jspm/nodelibs-http@1.7.1",
"os": "github:jspm/nodelibs-os@0.1.0",
"path": "github:jspm/nodelibs-path@0.1.0",
"process": "github:jspm/nodelibs-process@0.1.2",
"querystring": "github:jspm/nodelibs-querystring@0.1.0",
"stream": "github:jspm/nodelibs-stream@0.1.0",
"string_decoder": "github:jspm/nodelibs-string_decoder@0.1.0",
"util": "github:jspm/nodelibs-util@0.1.0"
},
"npm:hash.js@1.0.3": {
"inherits": "npm:inherits@2.0.1"
},
"npm:history@1.17.0": {
"child_process": "github:jspm/nodelibs-child_process@0.1.0",
"deep-equal": "npm:deep-equal@1.0.1",
"fs": "github:jspm/nodelibs-fs@0.1.2",
"invariant": "npm:invariant@2.2.0",
"process": "github:jspm/nodelibs-process@0.1.2",
"query-string": "npm:query-string@3.0.0",
"warning": "npm:warning@2.1.0"
},
"npm:https-browserify@0.0.0": {
"http": "github:jspm/nodelibs-http@1.7.1"
},
"npm:inherits@2.0.1": {
"util": "github:jspm/nodelibs-util@0.1.0"
},
"npm:invariant@2.2.0": {
"loose-envify": "npm:loose-envify@1.1.0",
"process": "github:jspm/nodelibs-process@0.1.2"
},
"npm:jstransform@10.1.0": {
"base62": "npm:base62@0.1.1",
"buffer": "github:jspm/nodelibs-buffer@0.1.0",
"esprima-fb": "npm:esprima-fb@13001.1001.0-dev-harmony-fb",
"fs": "github:jspm/nodelibs-fs@0.1.2",
"process": "github:jspm/nodelibs-process@0.1.2",
"source-map": "npm:source-map@0.1.31"
},
"npm:loose-envify@1.1.0": {
"js-tokens": "npm:js-tokens@1.0.2",
"process": "github:jspm/nodelibs-process@0.1.2",
"stream": "github:jspm/nodelibs-stream@0.1.0",
"util": "github:jspm/nodelibs-util@0.1.0"
},
"npm:methods@1.0.1": {
"http": "github:jspm/nodelibs-http@1.7.1"
},
"npm:miller-rabin@4.0.0": {
"bn.js": "npm:bn.js@4.6.2",
"brorand": "npm:brorand@1.0.5"
},
"npm:mime-db@1.12.0": {
"systemjs-json": "github:systemjs/plugin-json@0.1.0"
},
"npm:mime-types@2.0.14": {
"mime-db": "npm:mime-db@1.12.0"
},
"npm:mime@1.3.4": {
"assert": "github:jspm/nodelibs-assert@0.1.0",
"fs": "github:jspm/nodelibs-fs@0.1.2",
"path": "github:jspm/nodelibs-path@0.1.0",
"process": "github:jspm/nodelibs-process@0.1.2",
"systemjs-json": "github:systemjs/plugin-json@0.1.0"
},
"npm:os-browserify@0.1.2": {
"os": "github:jspm/nodelibs-os@0.1.0"
},
"npm:pako@0.2.8": {
"buffer": "github:jspm/nodelibs-buffer@0.1.0",
"process": "github:jspm/nodelibs-process@0.1.2"
},
"npm:parse-asn1@5.0.0": {
"asn1.js": "npm:asn1.js@4.3.0",
"browserify-aes": "npm:browserify-aes@1.0.5",
"buffer": "github:jspm/nodelibs-buffer@0.1.0",
"create-hash": "npm:create-hash@1.1.2",
"evp_bytestokey": "npm:evp_bytestokey@1.0.0",
"pbkdf2": "npm:pbkdf2@3.0.4",
"systemjs-json": "github:systemjs/plugin-json@0.1.0"
},
"npm:path-browserify@0.0.0": {
"process": "github:jspm/nodelibs-process@0.1.2"
},
"npm:pbkdf2@3.0.4": {
"buffer": "github:jspm/nodelibs-buffer@0.1.0",
"child_process": "github:jspm/nodelibs-child_process@0.1.0",
"create-hmac": "npm:create-hmac@1.1.4",
"crypto": "github:jspm/nodelibs-crypto@0.1.0",
"path": "github:jspm/nodelibs-path@0.1.0",
"process": "github:jspm/nodelibs-process@0.1.2",
"systemjs-json": "github:systemjs/plugin-json@0.1.0"
},
"npm:process-nextick-args@1.0.6": {
"process": "github:jspm/nodelibs-process@0.1.2"
},
"npm:process@0.11.2": {
"assert": "github:jspm/nodelibs-assert@0.1.0"
},
"npm:promise@7.1.1": {
"asap": "npm:asap@2.0.3",
"fs": "github:jspm/nodelibs-fs@0.1.2"
},
"npm:public-encrypt@4.0.0": {
"bn.js": "npm:bn.js@4.6.2",
"browserify-rsa": "npm:browserify-rsa@4.0.0",
"buffer": "github:jspm/nodelibs-buffer@0.1.0",
"create-hash": "npm:create-hash@1.1.2",
"crypto": "github:jspm/nodelibs-crypto@0.1.0",
"parse-asn1": "npm:parse-asn1@5.0.0",
"randombytes": "npm:randombytes@2.0.1"
},
"npm:punycode@1.3.2": {
"process": "github:jspm/nodelibs-process@0.1.2"
},
"npm:query-string@3.0.0": {
"strict-uri-encode": "npm:strict-uri-encode@1.1.0"
},
"npm:randombytes@2.0.1": {
"buffer": "github:jspm/nodelibs-buffer@0.1.0",
"crypto": "github:jspm/nodelibs-crypto@0.1.0",
"process": "github:jspm/nodelibs-process@0.1.2"
},
"npm:react-dom@0.14.6": {
"react": "npm:react@0.14.6"
},
"npm:react-google-analytics@0.2.0": {
"react": "npm:react@0.14.6"
},
"npm:react-router@1.0.3": {
"child_process": "github:jspm/nodelibs-child_process@0.1.0",
"fs": "github:jspm/nodelibs-fs@0.1.2",
"history": "npm:history@1.17.0",
"invariant": "npm:invariant@2.2.0",
"process": "github:jspm/nodelibs-process@0.1.2",
"warning": "npm:warning@2.1.0"
},
"npm:react@0.14.6": {
"envify": "npm:envify@3.4.0",
"fbjs": "npm:fbjs@0.6.1",
"process": "github:jspm/nodelibs-process@0.1.2"
},
"npm:readable-stream@1.0.27-1": {
"buffer": "github:jspm/nodelibs-buffer@0.1.0",
"core-util-is": "npm:core-util-is@1.0.2",
"events": "github:jspm/nodelibs-events@0.1.1",
"inherits": "npm:inherits@2.0.1",
"isarray": "npm:isarray@0.0.1",
"process": "github:jspm/nodelibs-process@0.1.2",
"stream": "github:jspm/nodelibs-stream@0.1.0",
"string_decoder": "npm:string_decoder@0.10.31"
},
"npm:readable-stream@2.0.5": {
"buffer": "github:jspm/nodelibs-buffer@0.1.0",
"core-util-is": "npm:core-util-is@1.0.2",
"events": "github:jspm/nodelibs-events@0.1.1",
"inherits": "npm:inherits@2.0.1",
"isarray": "npm:isarray@0.0.1",
"process": "github:jspm/nodelibs-process@0.1.2",
"process-nextick-args": "npm:process-nextick-args@1.0.6",
"string_decoder": "npm:string_decoder@0.10.31",
"util-deprecate": "npm:util-deprecate@1.0.2"
},
"npm:ripemd160@1.0.1": {
"buffer": "github:jspm/nodelibs-buffer@0.1.0",
"process": "github:jspm/nodelibs-process@0.1.2"
},
"npm:sha.js@2.4.4": {
"buffer": "github:jspm/nodelibs-buffer@0.1.0",
"fs": "github:jspm/nodelibs-fs@0.1.2",
"inherits": "npm:inherits@2.0.1",
"process": "github:jspm/nodelibs-process@0.1.2"
},
"npm:source-map@0.1.31": {
"amdefine": "npm:amdefine@1.0.0",
"fs": "github:jspm/nodelibs-fs@0.1.2",
"path": "github:jspm/nodelibs-path@0.1.0",
"process": "github:jspm/nodelibs-process@0.1.2"
},
"npm:stream-browserify@1.0.0": {
"events": "github:jspm/nodelibs-events@0.1.1",
"inherits": "npm:inherits@2.0.1",
"readable-stream": "npm:readable-stream@1.0.27-1"
},
"npm:string_decoder@0.10.31": {
"buffer": "github:jspm/nodelibs-buffer@0.1.0"
},
"npm:superagent@1.2.0": {
"buffer": "github:jspm/nodelibs-buffer@0.1.0",
"component-emitter": "npm:component-emitter@1.1.2",
"cookiejar": "npm:cookiejar@2.0.1",
"debug": "npm:debug@2.2.0",
"extend": "npm:extend@1.2.1",
"form-data": "npm:form-data@0.2.0",
"formidable": "npm:formidable@1.0.14",
"fs": "github:jspm/nodelibs-fs@0.1.2",
"http": "github:jspm/nodelibs-http@1.7.1",
"https": "github:jspm/nodelibs-https@0.1.0",
"methods": "npm:methods@1.0.1",
"mime": "npm:mime@1.3.4",
"qs": "npm:qs@2.3.3",
"readable-stream": "npm:readable-stream@1.0.27-1",
"reduce-component": "npm:reduce-component@1.0.1",
"stream": "github:jspm/nodelibs-stream@0.1.0",
"string_decoder": "github:jspm/nodelibs-string_decoder@0.1.0",
"systemjs-json": "github:systemjs/plugin-json@0.1.0",
"url": "github:jspm/nodelibs-url@0.1.0",
"util": "github:jspm/nodelibs-util@0.1.0",
"zlib": "github:jspm/nodelibs-zlib@0.1.0"
},
"npm:through@2.3.8": {
"process": "github:jspm/nodelibs-process@0.1.2",
"stream": "github:jspm/nodelibs-stream@0.1.0"
},
"npm:timers-browserify@1.4.2": {
"process": "npm:process@0.11.2"
},
"npm:ua-parser-js@0.7.10": {
"systemjs-json": "github:systemjs/plugin-json@0.1.0"
},
"npm:url@0.10.3": {
"assert": "github:jspm/nodelibs-assert@0.1.0",
"punycode": "npm:punycode@1.3.2",
"querystring": "npm:querystring@0.2.0",
"util": "github:jspm/nodelibs-util@0.1.0"
},
"npm:util-deprecate@1.0.2": {
"util": "github:jspm/nodelibs-util@0.1.0"
},
"npm:util@0.10.3": {
"inherits": "npm:inherits@2.0.1",
"process": "github:jspm/nodelibs-process@0.1.2"
},
"npm:vm-browserify@0.0.4": {
"indexof": "npm:indexof@0.0.1"
},
"npm:warning@2.1.0": {
"loose-envify": "npm:loose-envify@1.1.0",
"process": "github:jspm/nodelibs-process@0.1.2"
}
}
});

View file

12
public/src/app.js Normal file
View file

@ -0,0 +1,12 @@
import Vue from 'vue';
import App from './app.vue';
import store from './store';
import router from './router';
const app = new Vue({
router,
store,
...App,
});
export { app, router, store };

42
public/src/app.vue Normal file
View file

@ -0,0 +1,42 @@
<template>
<div id="app">
<h1 class="title has-text-centered header"><router-link to="/" exact>
match<span class="lighter">.audio</span>
</router-link></h1>
<div>
<router-view></router-view>
</div>
<footer class="footer">
<div class="container has-text-right">
<a href='https://twitter.com/MatchAudio'>Tweet</a> or <a href='https://github.com/kudos/match.audio'>Fork</a>. A work in progress by <a href='http://crem.in'>this guy</a>.
</div>
</footer>
</div>
</template>
<style>
body {
color: #445470;
background: #fff;
}
h1 {
background: #FE4365;
padding: 25px 0;
}
h1 a {
color: #fff;
}
h1 a:hover {
color: #ffacc5;
}
.title a:hover {
border-bottom: none;
}
h1 .lighter {
color: #ffacc5;
}
.footer {
margin-top: 50px;
padding-bottom: 40px;
}
</style>

View file

@ -0,0 +1,54 @@
<template>
<form role="form" method="post" action="/search" v-on:submit="submit">
<p class="control has-addons">
<input class="input is-expanded is-large" type="text" placeholder="Paste your link here" v-model="url">
<button type="submit" class="button is-primary is-large">
Share Music
</button>
</p>
</form>
</template>
<script>
import { musicSearch } from '../store/api';
export default {
name: 'search-view',
data() {
return {
url: '',
};
},
methods: {
submit (event) {
event.preventDefault();
musicSearch(this.url).end((req, res) => {
const item = res.body;
this.$router.push(`/${item.service}/${item.albumName ? 'track' : 'album'}/${item.externalId}`);
});
},
},
}
</script>
<style>
.button.is-primary {
background-color: #FE4365;
}
.button.is-primary:hover {
background-color: #E52A4C;
}
.button.is-primary:focus {
background-color: #E52A4C;
}
.input:active {
border-color: #FE4365;
}
.input:focus {
border-color: #FE4365;
}
form {
margin-bottom: 50px;
margin-top: 200px;
}
</style>

View file

@ -0,0 +1,8 @@
import { sync } from 'vuex-router-sync';
import { app, store, router } from './app';
document.addEventListener('DOMContentLoaded', () => { // eslint-disable-line no-undef
store.replaceState(window.__INITIAL_STATE__); // eslint-disable-line
sync(store, router);
app.$mount('#app');
});

View file

@ -0,0 +1,15 @@
import { app, router, store } from './app';
// This exported function will be called by `bundleRenderer`.
// This is where we perform data-prefetching to determine the
// state of our application before actually rendering it.
// Since data fetching is async, this function is expected to
// return a Promise that resolves to the app instance.
export default (context) => {
// set router's location
router.push(context.url);
store.replaceState(context.initialState);
return app;
};

View file

@ -0,0 +1,25 @@
import Vue from 'vue';
import Router from 'vue-router';
import index from '../views/index.vue';
import share from '../views/share.vue';
Vue.use(Router);
const router = new Router({
mode: 'history',
routes: [
{ path: '/', component: index },
{ path: '/:service/:type/:id', name: 'share', component: share },
],
});
router.afterEach((to) => {
if (typeof window !== 'undefined') {
ga('send', { // eslint-disable-line no-undef
hitType: 'pageview',
page: to.fullPath,
});
}
});
export default router;

14
public/src/store/api.js Normal file
View file

@ -0,0 +1,14 @@
import request from 'superagent';
import 'superagent-bluebird-promise';
export function fetchItem(service, type, id) {
return request.get(`/${service}/${type}/${id}.json`);
}
export function fetchRecents() {
return request.get('/recent');
}
export function musicSearch(url) {
return request.post('/search').send({ url });
}

37
public/src/store/index.js Normal file
View file

@ -0,0 +1,37 @@
import Vue from 'vue';
import Vuex from 'vuex';
import { fetchItem, fetchRecents } from './api';
Vue.use(Vuex);
const store = new Vuex.Store({
debug: true,
state: {
recents: [],
item: {},
services: [],
},
actions: {
// ensure data for rendering given list type
FETCH_RECENTS: ({ commit }) => fetchRecents()
.then(res => commit('SET_RECENTS', { recents: res.body.recents })),
FETCH_ITEM: ({ commit, state }, { service, type, id }) => fetchItem(service, type, id)
.then(item => {
return commit('SET_ITEM', { item })
}),
},
mutations: {
SET_RECENTS: (state, { recents }) => {
state.recents = recents; // eslint-disable-line no-param-reassign
},
SET_ITEM: (state, { item }) => {
state.item = item.body;
},
},
});
export default store;

149
public/src/style/style.css Normal file
View file

@ -0,0 +1,149 @@
/* app.vue */
body {
color: #445470;
background: #fff;
}
h1 {
background: #FE4365;
padding: 25px 0;
}
h1 a {
color: #fff;
}
h1 a:hover {
color: #ffacc5;
}
.title a:hover {
border-bottom: none;
}
h1 .lighter {
color: #ffacc5;
}
.footer {
margin-top: 50px;
padding-bottom: 40px;
}
/* index.vue */
.blurb {
margin-bottom: 50px;
}
.recently-shared {
margin-bottom: 50px;
}
.faq {
margin-bottom: 50px;
}
.faq p {
margin-bottom: 30px;
}
.home {
width: 600px;
margin-top: 40px;
}
p {
margin-bottom: 10px;
}
.recent .artwork {
margin-bottom: 30px;
}
.artwork {
position: relative;
width: 100%;
height: 0;
padding-bottom: 100%;
background-repeat: no-repeat;
background-size: cover;
border-radius: 5px;
}
/* search.vue */
.button.is-primary {
background-color: #FE4365;
}
.button.is-primary:hover {
background-color: #E52A4C;
}
.button.is-primary:focus {
background-color: #E52A4C;
}
.input:active {
border-color: #FE4365;
}
.input:focus {
border-color: #FE4365;
}
form {
margin-bottom: 50px;
margin-top: 200px;
}
/* share.vue */
.share-heading {
margin-bottom: 50px
}
.share-heading .title {
color: #8396b0;
}
.share-heading .title strong {
color: #445470;
font-weight: 700;
}
.artwork {
position: relative;
width: 100%;
height: 0;
padding-bottom: 100%;
background-repeat: no-repeat;
background-size: cover;
border-radius: 5px;
}
.artwork-youtube {
background-position: 50% 0%;
}
.service {
position: relative;
margin-bottom: 10px;
}
.service-link img {
margin-top: 20px;
margin-bottom: 20px;
height: 40px;
}
img {
vertical-align: middle;
}
.not-found {
opacity: 0.2;
}
.match {
position: relative;
}
.no-match {
position: absolute;
top: 10px;
right: 10px;
background: #fff;
color: #FE4365;
padding: 3px 6px;
border-radius: 3px;
opacity: 0.7;
font-weight: bold;
}
.loading-wrap {
position: absolute;
top: 0;left: 0;
background: #fff;
height: 100%;
width: 100%;
opacity: 0.8;
}
.loading {
position: absolute;
top: 35%;
left: 40%;
width: 20%;
}

124
public/src/views/index.vue Normal file
View file

@ -0,0 +1,124 @@
<template>
<div class="home container">
<search></search>
<div class="blurb">
<p>
Match Audio makes sharing from music services better. What happens when you share your favourite song on Spotify with a friend, but they don't use Spotify?
</p>
<p>
We match album and track links from Youtube, Rdio, Spotify, Deezer, Google Music, Xbox Music, Beats Music, and iTunes and give you back one link with matches we find on all of them.
</p>
</div>
<div class="recently-shared">
<h2 class="title is-2">Recently Shared</h2>
<ul class="columns is-multiline">
<li v-for="(item, index) in recents" class="column is-one-third ">
<router-link :to="{ name: 'share', params: { service: item.service, type: item.albumName ? 'track' : 'album', id: item.externalId }}"><div v-bind:style="{ backgroundImage: `url(${item.matches.find(function(el) { return el.service == item.service }).artworkLarge })` }" class="artwork">
</div></router-link>
</li>
</ul>
</div>
<div class="faq">
<h2 class="title is-2">Questions?</h2>
<h3 class="title is-3">Why would I want to use this?</h3>
<p>Sometimes when people want to share music they don't know what service their friends are using. Match Audio let's you take a link from one service and expand it into a link that supports all services.</p>
<h3 class="title is-3">I still don't get it.</h3>
<p>That's not actually a question, but that's ok. Here's an example: I'm listening to a cool new album I found on Google Play Music. So I go to the address bar (the box that sometimes says https://www.google.com in it) and copy the link to share with my friend. But my friend uses Spotify. So first I go to Match Audio and paste the link there, then grab the Match Audio link from the address bar and send them that link instead.</p>
<h3 class="title is-3">Where do I find a link to paste in the box?</h3>
<p>Most music services have a 'share' dialog for albums and tracks in their interface. If you have them open in a web browser instead of an app, you can simply copy and paste the address bar and we'll work out the rest.</p>
<h3 class="title is-3">Can I share playlists?</h3>
<p>Unfortunately not. Playlists would add a huge amount of complexity and would almost certainly cause the site to break the API limits imposed by some of the services we support.</p>
<h3 class="title is-3">Why don't you guys support Bandcamp, Amazon Music, Sony Music Unlimited ?</h3>
<p>Let me stop you there. Match Audio is open source, that means any capable programmer who wants to add other music services can look at our code and submit changes. If you're not a programmer, you can always submit a request and maybe we'll do it for you.</p>
</div>
<div>
<h2 class="title is-2">Tools</h2>
<div class="columns">
<p class="column is-half">
Download the Chrome Extension and get Match Audio links right from your address bar.
</p>
<p class="column is-half">
<a href="https://chrome.google.com/webstore/detail/kjfpkmfgcflggjaldcfnoppjlpnidolk"><img src="/assets/images/chrome-web-store.png" alt="Download the Chrome Extension" /></a>
</p>
</div>
</div>
</div>
</template>
<script>
import { fetchRecents } from '../store/api';
import search from '../components/search.vue';
export default {
name: 'index-view',
components: { search },
created () {
// fetch the data when the view is created and the data is
// already being observed
this.fetch();
},
data() {
return {
recents: {},
};
},
watch: {
'$route': 'fetch',
recents: function () {
if (typeof document !== 'undefined') {
const recents = this.$store.state.recents;
document.title = `Match Audio • Share Music`;
}
},
},
methods: {
fetch () {
if (!this.$store.state.recents) {
fetchRecents().then((res) => {
this.recents = res.body.recents;
});
} else {
this.recents = this.$store.state.recents;
}
},
},
}
</script>
<style>
.blurb {
margin-bottom: 50px;
}
.recently-shared {
margin-bottom: 50px;
}
.faq {
margin-bottom: 50px;
}
.faq p {
margin-bottom: 30px;
}
.home {
width: 600px;
margin-top: 40px;
}
p {
margin-bottom: 10px;
}
.recent .artwork {
margin-bottom: 30px;
}
.artwork {
position: relative;
width: 100%;
height: 0;
padding-bottom: 100%;
background-repeat: no-repeat;
background-size: cover;
border-radius: 5px;
}
</style>

146
public/src/views/share.vue Normal file
View file

@ -0,0 +1,146 @@
<template>
<div class="container" v-if="item.name">
<div class="share-heading">
<h3 class="title is-3">Matched {{ item.albumName ? 'tracks' : 'albums' }} for</h3>
<h2 class="title is-2"><strong>{{ item.name }}</strong> - {{ item.artist.name }}</h2>
</div>
<ul class="columns is-multiline">
<li v-for="match in item.matches" class="column is-2">
<div v-if="match.externalId && match.id != 152">
<a v-bind:href="match.streamUrl"><div v-bind:style="{ backgroundImage: `url(${match.artworkLarge})` }" class="artwork">
</div></a>
<div class='service-link has-text-centered'>
<a v-bind:href="match.streamUrl"><img v-bind:src="`/assets/images/${match.service}.png`" /></a>
</div>
</div>
<div v-if="match.matching || match.id === 152" class="service">
<div v-bind:style="{ backgroundImage: `url(${item.matches[0].artworkLarge})` }" class="artwork">
</div>
<div class='loading-wrap'>
<img src='/assets/images/eq.svg' class='loading' />
</div>
<div class='service-link has-text-centered'>
<img v-bind:src="`/assets/images/${match.service}.png`" />
</div>
</div>
<div class="service" v-if="!match.externalId && !match.matching">
<div v-bind:style="{ backgroundImage: `url(${item.matches[0].artworkLarge})` }" class="artwork not-found">
</div>
<div class='no-match'>
No Match
</div>
<div class='service-link has-text-centered not-found'>
<img v-bind:src="`/assets/images/${match.service}.png`" />
</div>
</div>
</li>
</ul>
</div>
</template>
<script>
import { fetchItem } from '../store/api';
export default {
name: 'share-view',
data() {
return {
item: {},
};
},
created () {
// fetch the data when the view is created and the data is
// already being observed
this.fetch();
this.interval = setInterval(() => {
this.fetch();
}, 1000);
},
watch: {
// call again the method if the route changes
'$route': 'fetch',
},
methods: {
fetch () {
const item = this.$store.state.item;
const id = this.$route.params.id;
if (item && item.externalId === id && (typeof window === 'undefined' || !item.matches.some(match => match.matching))) {
this.item = this.$store.state.item;
} else {
fetchItem(this.$route.params.service, this.$route.params.type, id).then((res) => {
if(!res.body.matches.some(match => match.matching)) {
clearInterval(this.interval);
}
this.item = res.body;
document.title = `Match Audio • ${this.item.artist.name} - ${this.item.name}`;
});
}
}
}
}
</script>
<style>
.share-heading {
margin-bottom: 50px
}
.share-heading .title {
color: #8396b0;
}
.share-heading .title strong {
color: #445470;
font-weight: 700;
}
.artwork {
position: relative;
width: 100%;
height: 0;
padding-bottom: 100%;
background-repeat: no-repeat;
background-size: cover;
background-position-x: center;
border-radius: 5px;
}
.service {
margin-bottom: 10px;
}
.service-link img {
margin-top: 20px;
margin-bottom: 20px;
height: 40px;
}
img {
vertical-align: middle;
}
.not-found {
opacity: 0.2;
}
.match {
position: relative;
}
.no-match {
position: absolute;
top: 10px;
right: 10px;
background: #fff;
color: #FE4365;
padding: 3px 6px;
border-radius: 3px;
opacity: 0.7;
font-weight: bold;
}
.loading-wrap {
position: absolute;
top: 0;left: 0;
background: #fff;
height: 100%;
width: 100%;
opacity: 0.8;
}
.loading {
position: absolute;
top: 35%;
left: 40%;
width: 20%;
}
</style>

View file

@ -1,259 +0,0 @@
body {
font-family: "Open Sans";
color: #445470;
}
html, body {
height: 100%;
}
header {
background: #FE4365;
}
.page-wrap {
min-height: 100%;
margin-bottom: -180px;
}
.page-wrap:after {
content: "";
display: block;
}
footer, .page-wrap:after {
margin-top: 80px;
height: 100px;
}
footer {
line-height: 100px;
text-align: right;
}
header h1 {
margin: 0;
padding: 0;
text-align: center;
font-weight: 300;
font-size: 2em;
line-height: 80px;
}
header h1 a {
color: #fff;
}
a {
color: #C04969;
}
a:hover {
color: #824F6D;
}
header h1 a:hover, header h1 a:focus{
color: #ffacc5;
text-decoration: none;
}
.home input[type="text"]:focus {
border-color: rgba(255, 68, 109, 0.8);
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075) inset, 0 0 5px rgba(255, 68, 109, 0.8);
outline: 0 none;
}
.faq ul {
padding: 0;
}
.faq li {
list-style: none;
}
.share header h1, .share header h1 {
text-align: left;
font-size: 1.5em;
line-height: 36px;
}
.audio-lighten {
color: #ffacc5;
}
.artist-lighten {
color: #8396b0;
font-weight: 300;
}
h2 {
font-size: 1.8em;
font-weight: 700;
margin-bottom: 40px;
}
h3 {
font-size: 1.5em;
color: #8396b0;
font-weight: 300;
}
.share-form {
margin-top: 25vh;
margin-bottom: 20px;
text-align: center;
}
.share-form form {
margin-bottom: 30px;
}
.share-form .alert {
margin-top: 20px;
}
.btn-custom {
background-color: #FE4365;
}
.btn-custom, .btn-custom:active, .btn-custom:hover, .btn-custom:focus {
color: #fff;
}
.blurb {
margin-bottom: 50px;
}
.recent .artwork {
margin-bottom: 30px;
}
.share-tools {
text-align: center;
margin-top: 40px;
font-weight: 300;
}
.share-tools img {
width: 20px;
}
.service {
padding: 40px 10px 10px 10px;
margin-bottom: 10px;
}
.matching-from {
position: absolute;
top: 10px;
left: 25px;
}
.source-service {
border-radius: 5px;
background: #eee;
}
.artwork {
position: relative;
width: 100%;
height: 0;
padding-bottom: 100%;
background-repeat: none;
background-size: cover;
border-radius: 5px;
}
.artwork-youtube {
background-position: 50% 0%;
}
.not-found {
opacity: 0.2;
}
.no-match {
position: absolute;
bottom: 80px;
right: 37px;
background: #fff;
color: #FE4365;
padding: 3px 6px;
border-radius: 3px;
opacity: 0.7;
font-weight: bold;
}
.youtube {
position: absolute;
font-weight: bold;
bottom: 65px;
left: 25px;
right: 25px;
padding: 10px;
opacity: 0.85;
background: #fff;
color: #FE4365;
}
.loading-wrap {
position: absolute;
top: 0;left: 0;
background: #fff;
height: 100%;
width: 100%;
opacity: 0.8;
}
.loading {
position: absolute;
top: 35%;
left: 40%;
width: 20%;
}
.service-link {
text-align: center;
}
.service-link a {
font-size: 1.8em;
color: #444;
}
.service-link a:hover {
text-decoration: none;
}
.service-link img {
height: 40px;
}
.error {
background: #FE4365;
color: #febdc9;
}
.error h1, .error h2 {
font-weight: 100;
}
.error .main h1 {
font-size: 2em;
margin-bottom: 20px;
color: #fff;
}
.error h2 {
color: #ff7c94;
font-size: 4em;
margin-top: 0px;
margin-bottom: 20px;
}
.error .col-md-12 {
margin-top: -1px;
}
.error a {
color: #fff;
}
.error-logo {
position: absolute;
top: 50px;
left: 15px;
}
.vertical-center {
min-height: 100%; /* Fallback for browsers do NOT support vh unit */
min-height: 100vh; /* These two lines are counted as one :-) */
display: flex;
align-items: center;
}