Dwayne Harris 5 years ago
parent
commit
0e6938b7e4
  1. 283
      package-lock.json
  2. 13
      package.json
  3. 163
      src/apps/gif-app/composer/app.tsx
  4. 24
      src/apps/gif-app/composer/gif.tsx
  5. BIN
      src/apps/gif-app/composer/giphy.png
  6. 12
      src/apps/gif-app/composer/index.ejs
  7. 6
      src/apps/gif-app/composer/index.tsx
  8. 63
      src/apps/gif-app/composer/webpack.config.ts
  9. 17
      src/apps/text-app/composer/app.tsx
  10. 2
      src/apps/text-app/composer/index.ejs
  11. 4
      src/apps/text-app/composer/index.tsx
  12. 1
      src/apps/text-app/composer/webpack.config.ts
  13. 16
      src/communicator/index.ts
  14. 145
      src/server/api/index.ts
  15. 14
      src/server/index.ts
  16. 17
      src/styles/default.scss
  17. 58
      src/types/index.ts
  18. 2
      tsconfig.json

283
package-lock.json

@ -45,6 +45,12 @@
"integrity": "sha512-/+CRPXpBDpo2RK9C68N3b2cOvO0Cf5B9aPijHsoDQTHivnGSObdOF2BRQOYjojWTDy6nQvMjmqRXIxH55VjxxA==", "integrity": "sha512-/+CRPXpBDpo2RK9C68N3b2cOvO0Cf5B9aPijHsoDQTHivnGSObdOF2BRQOYjojWTDy6nQvMjmqRXIxH55VjxxA==",
"dev": true "dev": true
}, },
"@types/caseless": {
"version": "0.12.2",
"resolved": "https://registry.npmjs.org/@types/caseless/-/caseless-0.12.2.tgz",
"integrity": "sha512-6ckxMjBBD8URvjB6J3NcnuAn5Pkl7t3TizAg+xdlzzQGSPSmBcXf8KoIH0ua/i+tio+ZRUHEXp0HEmvaR4kt0w==",
"dev": true
},
"@types/classnames": { "@types/classnames": {
"version": "2.2.9", "version": "2.2.9",
"resolved": "https://registry.npmjs.org/@types/classnames/-/classnames-2.2.9.tgz", "resolved": "https://registry.npmjs.org/@types/classnames/-/classnames-2.2.9.tgz",
@ -128,6 +134,31 @@
"integrity": "sha1-a9p9uGU/piZD9e5p6facEaOS46Y=", "integrity": "sha1-a9p9uGU/piZD9e5p6facEaOS46Y=",
"dev": true "dev": true
}, },
"@types/request": {
"version": "2.48.3",
"resolved": "https://registry.npmjs.org/@types/request/-/request-2.48.3.tgz",
"integrity": "sha512-3Wo2jNYwqgXcIz/rrq18AdOZUQB8cQ34CXZo+LUwPJNpvRAL86+Kc2wwI8mqpz9Cr1V+enIox5v+WZhy/p3h8w==",
"dev": true,
"requires": {
"@types/caseless": "*",
"@types/node": "*",
"@types/tough-cookie": "*",
"form-data": "^2.5.0"
},
"dependencies": {
"form-data": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz",
"integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==",
"dev": true,
"requires": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.6",
"mime-types": "^2.1.12"
}
}
}
},
"@types/source-list-map": { "@types/source-list-map": {
"version": "0.1.2", "version": "0.1.2",
"resolved": "https://registry.npmjs.org/@types/source-list-map/-/source-list-map-0.1.2.tgz", "resolved": "https://registry.npmjs.org/@types/source-list-map/-/source-list-map-0.1.2.tgz",
@ -140,6 +171,12 @@
"integrity": "sha512-78AdXtlhpCHT0K3EytMpn4JNxaf5tbqbLcbIRoQIHzpTIyjpxLQKRoxU55ujBXAtg3Nl2h/XWvfDa9dsMOd0pQ==", "integrity": "sha512-78AdXtlhpCHT0K3EytMpn4JNxaf5tbqbLcbIRoQIHzpTIyjpxLQKRoxU55ujBXAtg3Nl2h/XWvfDa9dsMOd0pQ==",
"dev": true "dev": true
}, },
"@types/tough-cookie": {
"version": "2.3.5",
"resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-2.3.5.tgz",
"integrity": "sha512-SCcK7mvGi3+ZNz833RRjFIxrn4gI1PPR3NtuIS+6vMkvmsGjosqTJwRt5bAEFLRz+wtJMWv8+uOnZf2hi2QXTg==",
"dev": true
},
"@types/uglify-js": { "@types/uglify-js": {
"version": "3.0.4", "version": "3.0.4",
"resolved": "https://registry.npmjs.org/@types/uglify-js/-/uglify-js-3.0.4.tgz", "resolved": "https://registry.npmjs.org/@types/uglify-js/-/uglify-js-3.0.4.tgz",
@ -557,7 +594,6 @@
"version": "0.2.4", "version": "0.2.4",
"resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz",
"integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==",
"dev": true,
"requires": { "requires": {
"safer-buffer": "~2.1.0" "safer-buffer": "~2.1.0"
} }
@ -603,8 +639,7 @@
"assert-plus": { "assert-plus": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
"dev": true
"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
}, },
"assign-symbols": { "assign-symbols": {
"version": "1.0.0", "version": "1.0.0",
@ -627,8 +662,7 @@
"asynckit": { "asynckit": {
"version": "0.4.0", "version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=",
"dev": true
"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
}, },
"atob": { "atob": {
"version": "2.1.2", "version": "2.1.2",
@ -664,14 +698,12 @@
"aws-sign2": { "aws-sign2": {
"version": "0.7.0", "version": "0.7.0",
"resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
"integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=",
"dev": true
"integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg="
}, },
"aws4": { "aws4": {
"version": "1.8.0", "version": "1.8.0",
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz",
"integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==",
"dev": true
"integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ=="
}, },
"balanced-match": { "balanced-match": {
"version": "1.0.0", "version": "1.0.0",
@ -743,7 +775,6 @@
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
"integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=",
"dev": true,
"requires": { "requires": {
"tweetnacl": "^0.14.3" "tweetnacl": "^0.14.3"
} }
@ -1014,8 +1045,7 @@
"caseless": { "caseless": {
"version": "0.12.0", "version": "0.12.0",
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
"integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=",
"dev": true
"integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw="
}, },
"chalk": { "chalk": {
"version": "2.4.2", "version": "2.4.2",
@ -1195,7 +1225,6 @@
"version": "1.0.8", "version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"dev": true,
"requires": { "requires": {
"delayed-stream": "~1.0.0" "delayed-stream": "~1.0.0"
} }
@ -1311,8 +1340,7 @@
"core-util-is": { "core-util-is": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
"dev": true
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
}, },
"create-ecdh": { "create-ecdh": {
"version": "4.0.3", "version": "4.0.3",
@ -1490,7 +1518,6 @@
"version": "1.14.1", "version": "1.14.1",
"resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
"integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
"dev": true,
"requires": { "requires": {
"assert-plus": "^1.0.0" "assert-plus": "^1.0.0"
} }
@ -1585,8 +1612,7 @@
"delayed-stream": { "delayed-stream": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
"dev": true
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
}, },
"delegates": { "delegates": {
"version": "1.0.0", "version": "1.0.0",
@ -1695,6 +1721,11 @@
"domelementtype": "1" "domelementtype": "1"
} }
}, },
"dotenv": {
"version": "8.2.0",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz",
"integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw=="
},
"duplexify": { "duplexify": {
"version": "3.7.1", "version": "3.7.1",
"resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz",
@ -1743,7 +1774,6 @@
"version": "0.1.2", "version": "0.1.2",
"resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
"integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=",
"dev": true,
"requires": { "requires": {
"jsbn": "~0.1.0", "jsbn": "~0.1.0",
"safer-buffer": "^2.1.0" "safer-buffer": "^2.1.0"
@ -2020,8 +2050,7 @@
"extend": { "extend": {
"version": "3.0.2", "version": "3.0.2",
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
"integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",
"dev": true
"integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
}, },
"extend-shallow": { "extend-shallow": {
"version": "3.0.2", "version": "3.0.2",
@ -2112,8 +2141,7 @@
"extsprintf": { "extsprintf": {
"version": "1.3.0", "version": "1.3.0",
"resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
"integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=",
"dev": true
"integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU="
}, },
"fast-decode-uri-component": { "fast-decode-uri-component": {
"version": "1.0.1", "version": "1.0.1",
@ -2210,6 +2238,54 @@
"integrity": "sha512-vNKxJHTEKNThjfrdJwHc7brvM6eVevuO5nTj6ez8ZQ1qbXTvGthucRF7S4vf2cr71QVnT70V34v0S1DyQsti0w==", "integrity": "sha512-vNKxJHTEKNThjfrdJwHc7brvM6eVevuO5nTj6ez8ZQ1qbXTvGthucRF7S4vf2cr71QVnT70V34v0S1DyQsti0w==",
"dev": true "dev": true
}, },
"file-loader": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/file-loader/-/file-loader-4.2.0.tgz",
"integrity": "sha512-+xZnaK5R8kBJrHK0/6HRlrKNamvVS5rjyuju+rnyxRGuwUJwpAMsVzUl5dz6rK8brkzjV6JpcFNjp6NqV0g1OQ==",
"dev": true,
"requires": {
"loader-utils": "^1.2.3",
"schema-utils": "^2.0.0"
},
"dependencies": {
"big.js": {
"version": "5.2.2",
"resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz",
"integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==",
"dev": true
},
"json5": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
"integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
"dev": true,
"requires": {
"minimist": "^1.2.0"
}
},
"loader-utils": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.2.3.tgz",
"integrity": "sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==",
"dev": true,
"requires": {
"big.js": "^5.2.2",
"emojis-list": "^2.0.0",
"json5": "^1.0.1"
}
},
"schema-utils": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.5.0.tgz",
"integrity": "sha512-32ISrwW2scPXHUSusP8qMg5dLUawKkyV+/qIEV9JdXKx+rsM6mi8vZY8khg2M69Qom16rtroWXD3Ybtiws38gQ==",
"dev": true,
"requires": {
"ajv": "^6.10.2",
"ajv-keywords": "^3.4.1"
}
}
}
},
"fill-range": { "fill-range": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
@ -2331,14 +2407,12 @@
"forever-agent": { "forever-agent": {
"version": "0.6.1", "version": "0.6.1",
"resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
"integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=",
"dev": true
"integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE="
}, },
"form-data": { "form-data": {
"version": "2.3.3", "version": "2.3.3",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
"integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
"dev": true,
"requires": { "requires": {
"asynckit": "^0.4.0", "asynckit": "^0.4.0",
"combined-stream": "^1.0.6", "combined-stream": "^1.0.6",
@ -3099,7 +3173,6 @@
"version": "0.1.7", "version": "0.1.7",
"resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
"integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
"dev": true,
"requires": { "requires": {
"assert-plus": "^1.0.0" "assert-plus": "^1.0.0"
} }
@ -3193,14 +3266,12 @@
"har-schema": { "har-schema": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
"integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=",
"dev": true
"integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI="
}, },
"har-validator": { "har-validator": {
"version": "5.1.3", "version": "5.1.3",
"resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz",
"integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==",
"dev": true,
"requires": { "requires": {
"ajv": "^6.5.5", "ajv": "^6.5.5",
"har-schema": "^2.0.0" "har-schema": "^2.0.0"
@ -3400,7 +3471,6 @@
"version": "1.2.0", "version": "1.2.0",
"resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
"integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=",
"dev": true,
"requires": { "requires": {
"assert-plus": "^1.0.0", "assert-plus": "^1.0.0",
"jsprim": "^1.2.2", "jsprim": "^1.2.2",
@ -3704,8 +3774,7 @@
"is-typedarray": { "is-typedarray": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
"integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=",
"dev": true
"integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo="
}, },
"is-utf8": { "is-utf8": {
"version": "0.2.1", "version": "0.2.1",
@ -3746,8 +3815,7 @@
"isstream": { "isstream": {
"version": "0.1.2", "version": "0.1.2",
"resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
"integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=",
"dev": true
"integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo="
}, },
"jmespath": { "jmespath": {
"version": "0.15.0", "version": "0.15.0",
@ -3769,8 +3837,7 @@
"jsbn": { "jsbn": {
"version": "0.1.1", "version": "0.1.1",
"resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
"integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=",
"dev": true
"integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM="
}, },
"json-parse-better-errors": { "json-parse-better-errors": {
"version": "1.0.2", "version": "1.0.2",
@ -3781,8 +3848,7 @@
"json-schema": { "json-schema": {
"version": "0.2.3", "version": "0.2.3",
"resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
"integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=",
"dev": true
"integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM="
}, },
"json-schema-traverse": { "json-schema-traverse": {
"version": "0.4.1", "version": "0.4.1",
@ -3792,8 +3858,7 @@
"json-stringify-safe": { "json-stringify-safe": {
"version": "5.0.1", "version": "5.0.1",
"resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
"integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=",
"dev": true
"integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus="
}, },
"json5": { "json5": {
"version": "0.5.1", "version": "0.5.1",
@ -3805,7 +3870,6 @@
"version": "1.4.1", "version": "1.4.1",
"resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
"integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=",
"dev": true,
"requires": { "requires": {
"assert-plus": "1.0.0", "assert-plus": "1.0.0",
"extsprintf": "1.3.0", "extsprintf": "1.3.0",
@ -4047,6 +4111,12 @@
} }
} }
}, },
"memorystream": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz",
"integrity": "sha1-htcJCzDORV1j+64S3aUaR93K+bI=",
"dev": true
},
"meow": { "meow": {
"version": "3.7.0", "version": "3.7.0",
"resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz",
@ -4113,14 +4183,12 @@
"mime-db": { "mime-db": {
"version": "1.40.0", "version": "1.40.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz",
"integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==",
"dev": true
"integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA=="
}, },
"mime-types": { "mime-types": {
"version": "2.1.24", "version": "2.1.24",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz",
"integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==", "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==",
"dev": true,
"requires": { "requires": {
"mime-db": "1.40.0" "mime-db": "1.40.0"
} }
@ -4540,6 +4608,79 @@
"sort-keys": "^1.0.0" "sort-keys": "^1.0.0"
} }
}, },
"npm-run-all": {
"version": "4.1.5",
"resolved": "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.5.tgz",
"integrity": "sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ==",
"dev": true,
"requires": {
"ansi-styles": "^3.2.1",
"chalk": "^2.4.1",
"cross-spawn": "^6.0.5",
"memorystream": "^0.3.1",
"minimatch": "^3.0.4",
"pidtree": "^0.3.0",
"read-pkg": "^3.0.0",
"shell-quote": "^1.6.1",
"string.prototype.padend": "^3.0.0"
},
"dependencies": {
"load-json-file": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz",
"integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=",
"dev": true,
"requires": {
"graceful-fs": "^4.1.2",
"parse-json": "^4.0.0",
"pify": "^3.0.0",
"strip-bom": "^3.0.0"
}
},
"parse-json": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
"integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=",
"dev": true,
"requires": {
"error-ex": "^1.3.1",
"json-parse-better-errors": "^1.0.1"
}
},
"path-type": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz",
"integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==",
"dev": true,
"requires": {
"pify": "^3.0.0"
}
},
"pify": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
"integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
"dev": true
},
"read-pkg": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz",
"integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=",
"dev": true,
"requires": {
"load-json-file": "^4.0.0",
"normalize-package-data": "^2.3.2",
"path-type": "^3.0.0"
}
},
"strip-bom": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
"integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=",
"dev": true
}
}
},
"npm-run-path": { "npm-run-path": {
"version": "2.0.2", "version": "2.0.2",
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz",
@ -4579,8 +4720,7 @@
"oauth-sign": { "oauth-sign": {
"version": "0.9.0", "version": "0.9.0",
"resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
"integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==",
"dev": true
"integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ=="
}, },
"object-assign": { "object-assign": {
"version": "4.1.1", "version": "4.1.1",
@ -4923,8 +5063,7 @@
"performance-now": { "performance-now": {
"version": "2.1.0", "version": "2.1.0",
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
"integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=",
"dev": true
"integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns="
}, },
"picomatch": { "picomatch": {
"version": "2.0.7", "version": "2.0.7",
@ -4932,6 +5071,12 @@
"integrity": "sha512-oLHIdio3tZ0qH76NybpeneBhYVj0QFTfXEFTc/B3zKQspYfYYkWYgFsmzo+4kvId/bQRcNkVeguI3y+CD22BtA==", "integrity": "sha512-oLHIdio3tZ0qH76NybpeneBhYVj0QFTfXEFTc/B3zKQspYfYYkWYgFsmzo+4kvId/bQRcNkVeguI3y+CD22BtA==",
"dev": true "dev": true
}, },
"pidtree": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.3.0.tgz",
"integrity": "sha512-9CT4NFlDcosssyg8KVFltgokyKZIFjoBxw8CTGy+5F38Y1eQWrt8tRayiUOXE+zVKQnYu5BR8JjCtvK3BcnBhg==",
"dev": true
},
"pify": { "pify": {
"version": "4.0.1", "version": "4.0.1",
"resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
@ -5140,8 +5285,7 @@
"psl": { "psl": {
"version": "1.4.0", "version": "1.4.0",
"resolved": "https://registry.npmjs.org/psl/-/psl-1.4.0.tgz", "resolved": "https://registry.npmjs.org/psl/-/psl-1.4.0.tgz",
"integrity": "sha512-HZzqCGPecFLyoRj5HLfuDSKYTJkAfB5thKBIkRHtGjWwY7p1dAyveIbXIq4tO0KYfDF2tHqPUgY9SDnGm00uFw==",
"dev": true
"integrity": "sha512-HZzqCGPecFLyoRj5HLfuDSKYTJkAfB5thKBIkRHtGjWwY7p1dAyveIbXIq4tO0KYfDF2tHqPUgY9SDnGm00uFw=="
}, },
"public-encrypt": { "public-encrypt": {
"version": "4.0.3", "version": "4.0.3",
@ -5198,8 +5342,7 @@
"qs": { "qs": {
"version": "6.5.2", "version": "6.5.2",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
"integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==",
"dev": true
"integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA=="
}, },
"query-string": { "query-string": {
"version": "4.3.4", "version": "4.3.4",
@ -5443,7 +5586,6 @@
"version": "2.88.0", "version": "2.88.0",
"resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz",
"integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==",
"dev": true,
"requires": { "requires": {
"aws-sign2": "~0.7.0", "aws-sign2": "~0.7.0",
"aws4": "^1.8.0", "aws4": "^1.8.0",
@ -5608,8 +5750,7 @@
"safer-buffer": { "safer-buffer": {
"version": "2.1.2", "version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
"dev": true
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
}, },
"sass-graph": { "sass-graph": {
"version": "2.2.4", "version": "2.2.4",
@ -5964,6 +6105,12 @@
"integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=",
"dev": true "dev": true
}, },
"shell-quote": {
"version": "1.7.2",
"resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.2.tgz",
"integrity": "sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg==",
"dev": true
},
"signal-exit": { "signal-exit": {
"version": "3.0.2", "version": "3.0.2",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
@ -6195,7 +6342,6 @@
"version": "1.16.1", "version": "1.16.1",
"resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz",
"integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==",
"dev": true,
"requires": { "requires": {
"asn1": "~0.2.3", "asn1": "~0.2.3",
"assert-plus": "^1.0.0", "assert-plus": "^1.0.0",
@ -6421,6 +6567,17 @@
} }
} }
}, },
"string.prototype.padend": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.0.0.tgz",
"integrity": "sha1-86rvfBcZ8XDF6rHDK/eA2W4h8vA=",
"dev": true,
"requires": {
"define-properties": "^1.1.2",
"es-abstract": "^1.4.3",
"function-bind": "^1.0.2"
}
},
"string.prototype.trimleft": { "string.prototype.trimleft": {
"version": "2.1.0", "version": "2.1.0",
"resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.0.tgz", "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.0.tgz",
@ -6706,7 +6863,6 @@
"version": "2.4.3", "version": "2.4.3",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz",
"integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==",
"dev": true,
"requires": { "requires": {
"psl": "^1.1.24", "psl": "^1.1.24",
"punycode": "^1.4.1" "punycode": "^1.4.1"
@ -6715,8 +6871,7 @@
"punycode": { "punycode": {
"version": "1.4.1", "version": "1.4.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
"integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=",
"dev": true
"integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4="
} }
} }
}, },
@ -6854,7 +7009,6 @@
"version": "0.6.0", "version": "0.6.0",
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
"integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
"dev": true,
"requires": { "requires": {
"safe-buffer": "^5.0.1" "safe-buffer": "^5.0.1"
} }
@ -6862,8 +7016,7 @@
"tweetnacl": { "tweetnacl": {
"version": "0.14.5", "version": "0.14.5",
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
"integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=",
"dev": true
"integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q="
}, },
"typedarray": { "typedarray": {
"version": "0.0.6", "version": "0.0.6",
@ -7062,8 +7215,7 @@
"uuid": { "uuid": {
"version": "3.3.3", "version": "3.3.3",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz",
"integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==",
"dev": true
"integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ=="
}, },
"v8-compile-cache": { "v8-compile-cache": {
"version": "2.0.3", "version": "2.0.3",
@ -7085,7 +7237,6 @@
"version": "1.10.0", "version": "1.10.0",
"resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
"integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
"dev": true,
"requires": { "requires": {
"assert-plus": "^1.0.0", "assert-plus": "^1.0.0",
"core-util-is": "1.0.2", "core-util-is": "1.0.2",

13
package.json

@ -5,8 +5,10 @@
"private": true, "private": true,
"scripts": { "scripts": {
"start": "node dist/server/index.js", "start": "node dist/server/index.js",
"build": "tsc",
"build:text-app": "webpack --config src/apps/text-app/composer/webpack.config.ts"
"build:server": "tsc",
"build:text-app": "webpack --config src/apps/text-app/composer/webpack.config.ts",
"build:gif-app": "webpack --config src/apps/gif-app/composer/webpack.config.ts",
"build": "run-s build:server build:text-app build:gif-app"
}, },
"devDependencies": { "devDependencies": {
"@types/classnames": "^2.2.9", "@types/classnames": "^2.2.9",
@ -14,12 +16,15 @@
"@types/mini-css-extract-plugin": "^0.8.0", "@types/mini-css-extract-plugin": "^0.8.0",
"@types/react": "^16.9.9", "@types/react": "^16.9.9",
"@types/react-dom": "^16.9.2", "@types/react-dom": "^16.9.2",
"@types/request": "^2.48.3",
"@types/webpack": "^4.39.5", "@types/webpack": "^4.39.5",
"bulma": "^0.8.0", "bulma": "^0.8.0",
"css-loader": "^3.2.0", "css-loader": "^3.2.0",
"file-loader": "^4.2.0",
"html-webpack-plugin": "^3.2.0", "html-webpack-plugin": "^3.2.0",
"mini-css-extract-plugin": "^0.8.0", "mini-css-extract-plugin": "^0.8.0",
"node-sass": "^4.12.0", "node-sass": "^4.12.0",
"npm-run-all": "^4.1.5",
"pino-pretty": "^3.2.2", "pino-pretty": "^3.2.2",
"sass-loader": "^8.0.0", "sass-loader": "^8.0.0",
"style-loader": "^1.0.0", "style-loader": "^1.0.0",
@ -34,9 +39,11 @@
"@fortawesome/free-solid-svg-icons": "^5.11.2", "@fortawesome/free-solid-svg-icons": "^5.11.2",
"@fortawesome/react-fontawesome": "^0.1.7", "@fortawesome/react-fontawesome": "^0.1.7",
"classnames": "^2.2.6", "classnames": "^2.2.6",
"dotenv": "^8.2.0",
"fastify": "^2.10.0", "fastify": "^2.10.0",
"fastify-static": "^2.5.0", "fastify-static": "^2.5.0",
"react": "^16.10.2", "react": "^16.10.2",
"react-dom": "^16.10.2"
"react-dom": "^16.10.2",
"request": "^2.88.0"
} }
} }

163
src/apps/gif-app/composer/app.tsx

@ -0,0 +1,163 @@
import React, { FC, useState, useEffect } from 'react'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faSearch } from '@fortawesome/free-solid-svg-icons'
import { Communicator } from '../../../communicator'
import classNames from 'classnames'
import Gif from './gif'
import { ClassDictionary, GiphyGif } from '../../../types'
const giphyIcon = require('./giphy.png')
import '../../../styles/default.scss'
type APIResponse = GiphyGif[]
interface Props {
communicator: Communicator
}
const useDebounce = (value: string, delay = 500) => {
const [valueD, setValueD] = useState(value)
useEffect(() => {
const handler = setTimeout(() => {
setValueD(value)
}, delay)
return () => {
clearTimeout(handler)
}
}, [value, delay])
return valueD
}
const App: FC<Props> = ({ communicator }) => {
const [posting, setPosting] = useState(false)
const [searching, setSearching] = useState(false)
const [search, setSearch] = useState('')
const searchD = useDebounce(search)
const [gifs, setGifs] = useState<GiphyGif[]>([])
const [selected, setSelected] = useState('')
const buttonStyle: ClassDictionary = {
'button': true,
'is-primary': true,
'is-loading': posting,
}
const controlStyle: ClassDictionary = {
'control': true,
'has-icons-left': true,
'is-loading': searching,
}
useEffect(() => {
const init = async () => {
try {
const content = await communicator.init()
if (content && content.parent && content.parent.data && content.parent.data.search) {
setSearch(content.parent.data.search)
}
await communicator.setHeight(1000)
} catch (err) {
console.error(err)
}
}
init()
}, [])
useEffect(() => {
const doTrending = async () => {
try {
const response = await fetch('/api/gifs/home')
setGifs(await response.json() as APIResponse)
} catch (err) {
console.error(err)
}
}
const doSearch = async () => {
try {
setSearching(true)
const response = await fetch(`/api/gifs/search?q=${search}`)
setGifs(await response.json() as APIResponse)
} catch (err) {
console.error(err)
}
setSearching(false)
}
if (!search) {
doTrending()
} else if (search.length > 2) {
doSearch()
}
}, [searchD])
const handleSearchChange = (search: string) => {
setSearch(search)
}
const post = async () => {
try {
const gif = gifs.find(g => g.id === selected)
if (!gif) return
setPosting(true)
await communicator.post({
attachments: [{
url: gif.images.fixed_height.url,
text: gif.title,
}],
data: {
search,
},
visible: true,
})
setSearch('')
setSelected('')
} catch (err) {
console.error(err)
}
setPosting(false)
}
return (
<div>
<div className="field">
<p className={classNames(controlStyle)}>
<input className="input" type="text" placeholder="Search" value={search} onChange={(e) => handleSearchChange(e.target.value)} />
<span className="icon is-small is-left">
<FontAwesomeIcon icon={faSearch} />
</span>
</p>
</div>
<div className="gifs is-flex">
{gifs.map(gif => <Gif key={gif.id} gif={gif} selected={gif.id === selected} onSelect={setSelected} />)}
</div>
<nav className="level">
<div className="level-left">
<div className="level-item">
<img src={giphyIcon} />
</div>
</div>
<div className="level-right">
<div className="level-item">
<button className={classNames(buttonStyle)} onClick={() => post()} disabled={!selected}>Post</button>
</div>
</div>
</nav>
</div>
)
}
export default App

24
src/apps/gif-app/composer/gif.tsx

@ -0,0 +1,24 @@
import React, { FC, useState, useEffect } from 'react'
import classNames from 'classnames'
import { ClassDictionary, GiphyGif } from '../../../types'
interface Props {
gif: GiphyGif
selected: boolean
onSelect: (id: string) => void
}
const Gif: FC<Props> = ({ gif, selected, onSelect }) => {
const classes: ClassDictionary = {
gif: true,
selected,
}
return (
<div className={classNames(classes)} onClick={() => onSelect(gif.id)}>
<img src={gif.images.fixed_height.url} alt={gif.title} />
</div>
)
}
export default Gif

BIN
src/apps/gif-app/composer/giphy.png

After

Width: 101  |  Height: 36  |  Size: 1.6 KiB

12
src/apps/gif-app/composer/index.ejs

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>GIF App</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<div id="app"></div>
</body>
</html>

6
src/apps/gif-app/composer/index.tsx

@ -0,0 +1,6 @@
import React from 'react'
import { render } from 'react-dom'
import App from './app'
import { Communicator } from '../../../communicator'
render(<App communicator={new Communicator('e396113e76dffaa2ad6c')} />, document.getElementById('app'))

63
src/apps/gif-app/composer/webpack.config.ts

@ -0,0 +1,63 @@
import { resolve } from 'path'
import { Configuration } from 'webpack'
import HtmlWebpackPlugin from 'html-webpack-plugin'
import MiniCssExtractPlugin from 'mini-css-extract-plugin'
const config: Configuration = {
mode: 'development',
devtool: 'eval-source-map',
entry: {
app: resolve(__dirname, './index.tsx'),
},
output: {
path: resolve(__dirname, '../../../../dist/apps/gif-app/'),
filename: '[name].js',
},
optimization: {
splitChunks: {
chunks: 'all',
},
},
resolve: {
extensions: ['.ts', '.tsx', '.js', '.png'],
},
module: {
rules: [
{
test: /\.ts(x?)$/,
exclude: /node_modules/,
use: 'ts-loader',
},
{
test: /\.scss$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
{
loader: 'sass-loader',
options: {
sourceMap: true,
},
},
],
},
{
test: /\.(jpe?g|gif|png|svg)$/,
use: ['file-loader'],
},
],
},
plugins: [
new HtmlWebpackPlugin({
title: 'GIF App',
hash: true,
template: resolve(__dirname, './index.ejs'),
filename: 'composer.html',
}),
new MiniCssExtractPlugin({
filename: '[name].css',
}),
],
}
export default config

17
src/apps/text-app/composer/app.tsx

@ -3,7 +3,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faEyeSlash } from '@fortawesome/free-solid-svg-icons' import { faEyeSlash } from '@fortawesome/free-solid-svg-icons'
import { Communicator } from '../../../communicator' import { Communicator } from '../../../communicator'
import classNames from 'classnames' import classNames from 'classnames'
import { ClassDictionary } from '../../../types'
import { ClassDictionary, Post } from '../../../types'
import '../../../styles/default.scss' import '../../../styles/default.scss'
@ -16,6 +16,7 @@ const App: FC<Props> = ({ communicator }) => {
const [content, setContent] = useState('') const [content, setContent] = useState('')
const [cover, setCover] = useState('') const [cover, setCover] = useState('')
const [posting, setPosting] = useState(false) const [posting, setPosting] = useState(false)
const [parent, setParent] = useState<Post | null>(null)
const charactersLeft = maxCharacters - content.length const charactersLeft = maxCharacters - content.length
const showCharactersLeft = charactersLeft < (maxCharacters / 2) const showCharactersLeft = charactersLeft < (maxCharacters / 2)
@ -31,10 +32,14 @@ const App: FC<Props> = ({ communicator }) => {
'is-loading': posting, 'is-loading': posting,
} }
const buttonText = parent ? 'Reply!' : 'Post!'
useEffect(() => { useEffect(() => {
const init = async () => { const init = async () => {
try { try {
await communicator.init()
const response = await communicator.init()
if (response!.parent) setParent(response!.parent)
await communicator.setHeight(document.body.offsetHeight) await communicator.setHeight(document.body.offsetHeight)
} catch (err) { } catch (err) {
console.error('App Component: ', err) console.error('App Component: ', err)
@ -49,7 +54,11 @@ const App: FC<Props> = ({ communicator }) => {
try { try {
setPosting(true) setPosting(true)
await communicator.post(true, content, cover)
await communicator.post({
text: content,
cover,
visible: true,
})
setContent('') setContent('')
setCover('') setCover('')
} catch (err) { } catch (err) {
@ -85,7 +94,7 @@ const App: FC<Props> = ({ communicator }) => {
<div className="level-right"> <div className="level-right">
<div className="level-item"> <div className="level-item">
<button className={classNames(buttonStyle)} onClick={() => post()} disabled={buttonDisabled}>Post!</button>
<button className={classNames(buttonStyle)} onClick={() => post()} disabled={buttonDisabled}>{buttonText}</button>
</div> </div>
</div> </div>
</nav> </nav>

2
src/apps/text-app/composer/index.ejs

@ -2,7 +2,7 @@
<html> <html>
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<title>Flexor</title>
<title>Text App</title>
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
</head> </head>

4
src/apps/text-app/composer/index.tsx

@ -3,6 +3,4 @@ import { render } from 'react-dom'
import App from './app' import App from './app'
import { Communicator } from '../../../communicator' import { Communicator } from '../../../communicator'
const communicator = new Communicator('1c28b52e4b1c93c0cc78')
render(<App communicator={communicator} />, document.getElementById('app'))
render(<App communicator={new Communicator('1c28b52e4b1c93c0cc78')} />, document.getElementById('app'))

1
src/apps/text-app/composer/webpack.config.ts

@ -11,7 +11,6 @@ const config: Configuration = {
}, },
output: { output: {
path: resolve(__dirname, '../../../../dist/apps/text-app/'), path: resolve(__dirname, '../../../../dist/apps/text-app/'),
// publicPath: '/',
filename: '[name].js', filename: '[name].js',
}, },
optimization: { optimization: {

16
src/communicator/index.ts

@ -1,6 +1,9 @@
import { Post } from '../types'
export interface MessageContent { export interface MessageContent {
[key: string]: any [key: string]: any
height?: number height?: number
parent?: Post
} }
export interface IncomingMessageData { export interface IncomingMessageData {
@ -26,9 +29,7 @@ interface ListenerCollection {
[name: string]: Listener [name: string]: Listener
} }
interface AppSettings {
[key: string]: any
}
type PostOptions = Post
export class Communicator { export class Communicator {
private origin = 'http://localhost:8080' private origin = 'http://localhost:8080'
@ -88,12 +89,7 @@ export class Communicator {
return this.postAndReceive('setHeight', { height }) return this.postAndReceive('setHeight', { height })
} }
async post(visible: boolean, text?: string, cover?: string, data?: object) {
return this.postAndReceive('post', {
visible,
text,
cover,
data,
})
async post(options: PostOptions) {
return this.postAndReceive('post', options)
} }
} }

145
src/server/api/index.ts

@ -0,0 +1,145 @@
import {
FastifyInstance,
RouteShorthandOptions,
Plugin,
DefaultQuery,
DefaultParams,
DefaultHeaders,
DefaultBody,
JSONSchema,
} from 'fastify'
import { Server, IncomingMessage, ServerResponse } from 'http'
import request from 'request'
import { PluginOptions, GiphyResponse } from '../../types'
interface FetchOptions {
url: string
params?: string[][]
method?: string
}
const paramsToString = (params: string[][]) => params.map(p => p.join('=')).join('&')
const giphyGifSchema: JSONSchema = {
type: 'object',
properties: {
type: { type: 'string' },
id: { type: 'string' },
slug: { type: 'string' },
url: { type: 'string' },
bitly_url: { type: 'string' },
embed_url: { type: 'string' },
title: { type: 'string' },
images: {
type: 'object',
properties: {
fixed_height: {
type: 'object',
properties: {
url: { type: 'string' },
},
},
fixed_height_still: {
type: 'object',
properties: {
url: { type: 'string' },
},
},
fixed_height_downsampled: {
type: 'object',
properties: {
url: { type: 'string' },
},
},
},
},
},
}
async function fetch<T = any>(options: FetchOptions) {
const { url, params = [], method = 'get' } = options
const uri = params.length > 0 ? `${url}?${paramsToString(params)}` : url
return new Promise<T>((resolve, reject) => {
request({
uri,
method,
json: true,
}, function(error, response, body) {
if (error) {
reject(error)
return
}
resolve(body)
})
})
}
function gifHomeRoute(server: FastifyInstance<Server, IncomingMessage, ServerResponse>) {
const options: RouteShorthandOptions = {
schema: {
response: {
200: {
type: 'array',
items: giphyGifSchema,
},
},
},
}
server.get<DefaultQuery, DefaultParams, DefaultHeaders, DefaultBody>('/api/gifs/home', options, async (request, reply) => {
const response = await fetch<GiphyResponse>({
url: `${process.env.GIPHY_API_ENDPOINT!}/v1/gifs/trending`,
params: [['api_key', process.env.GIPHY_API_KEY!], ['limit', '20']],
})
return response.data
})
}
function gifSearchRoute(server: FastifyInstance<Server, IncomingMessage, ServerResponse>) {
interface Query {
q: string
}
const options: RouteShorthandOptions = {
schema: {
querystring: {
type: 'object',
properties: {
q: { type: 'string' },
},
},
response: {
200: {
type: 'array',
items: giphyGifSchema,
},
},
},
}
server.get<Query, DefaultParams, DefaultHeaders, DefaultBody>('/api/gifs/search', options, async (request, reply) => {
const q = request.query.q ? request.query.q.trim() : ''
if (q.length < 3) {
reply.code(400)
return
}
const response = await fetch<GiphyResponse>({
url: `${process.env.GIPHY_API_ENDPOINT!}/v1/gifs/search`,
params: [['api_key', process.env.GIPHY_API_KEY!], ['limit', '20'], ['q', q]],
})
return response.data
})
}
const plugin: Plugin<Server, IncomingMessage, ServerResponse, PluginOptions> = async server => {
gifHomeRoute(server)
gifSearchRoute(server)
}
export default plugin

14
src/server/index.ts

@ -1,22 +1,28 @@
import { config } from 'dotenv'
import { resolve } from 'path' import { resolve } from 'path'
import fastify from 'fastify' import fastify from 'fastify'
import fastifyStatic from 'fastify-static' import fastifyStatic from 'fastify-static'
const port = 8082
import api from './api'
config()
const server = fastify({ const server = fastify({
logger: { logger: {
level: 'info',
prettyPrint: true,
level: process.env.LOGGER_LEVEL,
prettyPrint: process.env.LOGGER_PRETTY_PRINT === 'true',
} }
}) })
server.register(api)
server.register(fastifyStatic, { server.register(fastifyStatic, {
root: resolve(__dirname, '..', 'apps'), root: resolve(__dirname, '..', 'apps'),
}) })
const start = async () => { const start = async () => {
try { try {
await server.listen(port)
await server.listen(process.env.PORT!)
} catch (err) { } catch (err) {
process.exit(1) process.exit(1)
} }

17
src/styles/default.scss

@ -31,3 +31,20 @@ $body-size: 14px;
body { body {
padding: 10px; padding: 10px;
} }
div.gifs {
display: flex;
flex-wrap: wrap;
}
div.gif {
margin: 5px;
img {
height: 100px;
}
}
.gif.selected {
border: solid 3px $green;
}

58
src/types/index.ts

@ -1,3 +1,61 @@
export interface ClassDictionary { export interface ClassDictionary {
[name: string]: boolean [name: string]: boolean
} }
export interface PluginOptions {
}
export interface Attachment {
url: string
text?: string
cover?: string
}
export interface PostData {
[key: string]: any
}
export interface Post {
text?: string
cover?: string
attachments?: Attachment[]
data?: PostData
visible: boolean
}
export interface GiphyGif {
type: string
id: string
slug: string
url: string
bitly_url: string
embed_url: string
username: string
source: string
rating: string
content_url: string
title: string
images: {
fixed_height: {
url: string
}
fixed_height_still: {
url: string
}
fixed_height_downsampled: {
url: string
}
}
}
export interface GiphyPagination {
offset: number
total_count: number
count: number
}
export interface GiphyResponse {
data: GiphyGif[]
pagination: GiphyPagination
}

2
tsconfig.json

@ -1,6 +1,6 @@
{ {
"compilerOptions": { "compilerOptions": {
"outDir": "./dist/server/",
"outDir": "./dist/",
"baseUrl": ".", "baseUrl": ".",
"sourceMap": true, "sourceMap": true,
"strict": true, "strict": true,

Loading…
Cancel
Save