├── .gitignore ├── README.md ├── data ├── dev.json ├── effectivealtruism.json ├── rhyslindmark.json └── tokeneconomy.json ├── package-lock.json ├── package.json ├── public ├── favicon.ico ├── index.html ├── manifest.json ├── niel.jpg ├── rhyslindmark.jpg └── tecon.png ├── scripts └── publishToIPFS.js ├── server.js └── src ├── AddTokensButton.js ├── App.js ├── App.test.js ├── BeneficiaryCard.js ├── ClaimTokensButton.js ├── ContractCard.css ├── ContractInterface.css ├── ContractInterface.js ├── CreatorPage.css ├── CreatorPage.js ├── Deploy.css ├── Deploy.js ├── EtherscanLink.css ├── EtherscanLink.js ├── FAQ.css ├── FAQ.js ├── FundButton.js ├── FunderCard.js ├── Home.css ├── Home.js ├── Nav.css ├── Nav.js ├── PageEditor.js ├── RefundButton.js ├── SetMinAmountButton.js ├── Web3Controller.js ├── Web3Hub.css ├── Web3Hub.js ├── Web3Store.js ├── WithdrawButton.js ├── creatorsToIPFSMap.json ├── editorStyles.css ├── font-awesome ├── HELP-US-OUT.txt ├── css │ ├── font-awesome.css │ └── font-awesome.min.css ├── fonts │ ├── FontAwesome.otf │ ├── fontawesome-webfont.eot │ ├── fontawesome-webfont.svg │ ├── fontawesome-webfont.ttf │ ├── fontawesome-webfont.woff │ └── fontawesome-webfont.woff2 ├── less │ ├── animated.less │ ├── bordered-pulled.less │ ├── core.less │ ├── fixed-width.less │ ├── font-awesome.less │ ├── icons.less │ ├── larger.less │ ├── list.less │ ├── mixins.less │ ├── path.less │ ├── rotated-flipped.less │ ├── screen-reader.less │ ├── stacked.less │ └── variables.less └── scss │ ├── _animated.scss │ ├── _bordered-pulled.scss │ ├── _core.scss │ ├── _fixed-width.scss │ ├── _icons.scss │ ├── _larger.scss │ ├── _list.scss │ ├── _mixins.scss │ ├── _path.scss │ ├── _rotated-flipped.scss │ ├── _screen-reader.scss │ ├── _stacked.scss │ ├── _variables.scss │ └── font-awesome.scss ├── index.css ├── index.js ├── logo.svg ├── normalize.css ├── registerServiceWorker.js ├── skeleton.css └── toolbarPlugin.css /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /build 11 | 12 | # misc 13 | .DS_Store 14 | .env.local 15 | .env.development.local 16 | .env.test.local 17 | .env.production.local 18 | 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # StakeTree Site 2 | This is still a work in progress so stay tuned as this evolves. 3 | 4 | ## Overview 5 | The StakeTree site is built on create-react-app infrastructure with some adjustments. To develop locally, clone this repo and install the local modules: 6 | ``` 7 | npm install 8 | ``` 9 | Once that's completed. There's two parts to the site. The production server & the development mode. To start the server run this: 10 | ``` 11 | npm start 12 | ``` 13 | This fires up the node server situated in `server.js`. It serves the index.html & also provides a fallback for contract information at `/contract`, that's used by the creator page. To access the site visit: `http://localhost:3000`. 14 | 15 | However, the server only serves the bundled JS files. So this is exactly how production will look like. To work locally on the client-side code (React + a few more other libs), you'll need to use the dev mode. This is the traditional create-react-app dev setup with hot reloading & more. 16 | ``` 17 | npm run dev 18 | ``` 19 | It'll ask you setup the port on a new location if you have the server running too. So usually you can access the dev site at `http://localhost:3001` or if you're only running the dev mode, it'll also be on `http://localhost:3000`. 20 | 21 | TIP: It's not needed to run both the server & dev mode to develop on this. 22 | 23 | Now in dev mode, you can edit the React code and it will update automatically in your browser. 24 | Once you have completed your code, you have to bundle your JS code to be rolled up for production. To build it, run this: 25 | ``` 26 | npm run build 27 | ``` 28 | And remember to commit these files too. Verify that your code has bundled correctly by running the production code using the command mentioned earlier: `npm start`. 29 | 30 | If it all looks good. The code should be all good for review. Send a pull request over and we can go from there. -------------------------------------------------------------------------------- /data/dev.json: -------------------------------------------------------------------------------- 1 | { 2 | "contractAddress": "0x8c79ec3f260b067157b0a7db0bb465f90b87f8f1", 3 | "title": "StakeTree Development Fund", 4 | "avatar": "niel.jpg", 5 | "description": {"entityMap":{"0":{"type":"LINK","mutability":"MUTABLE","data":{"href":"https://twitter.com/nieldlr","rel":"noopener noreferrer","target":"_blank","url":"https://twitter.com/nieldlr"}},"1":{"type":"LINK","mutability":"MUTABLE","data":{"href":"https://trello.com/b/ThPpLwFm/staketree-transparent-roadmap","rel":"noopener noreferrer","target":"_blank","url":"https://trello.com/b/ThPpLwFm/staketree-transparent-roadmap"}},"2":{"type":"LINK","mutability":"MUTABLE","data":{"href":"https://twitter.com/staketree","rel":"noopener noreferrer","target":"_blank","url":"https://twitter.com/staketree"}},"3":{"type":"LINK","mutability":"MUTABLE","data":{"href":"https://github.com/StakeTree","rel":"noopener noreferrer","target":"_blank","url":"https://github.com/StakeTree"}}},"blocks":[{"key":"tuaj","text":"Hi everyone. I'm Niel, the founder of StakeTree.","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[{"offset":17,"length":4,"key":0}],"data":{}},{"key":"dgrh8","text":"\nThis dev fund is my only source of funding right now. I would really appreciate any help with bringing this ecosystem to the world.","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"ammd3","text":"","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"ask8s","text":"StakeTree uses smart contracts on Ethereum, where creators & funders can back projects with no intermediaries, fees and instant settlement.","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"ag4jo","text":"","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"24diq","text":"There's lots more planned for StakeTree:","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"go3f","text":"","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"54v1c","text":"Creating a simple UI for funders & creators to create, fund & withdraw from contracts.","type":"unordered-list-item","depth":0,"inlineStyleRanges":[{"offset":0,"length":20,"style":"BOLD"}],"entityRanges":[],"data":{}},{"key":"7mk9u","text":"Develop funding tiers. This is where creators can reward dedicated backers with special rewards/access. Think tiers like Kickstarter & Patreon.","type":"unordered-list-item","depth":0,"inlineStyleRanges":[{"offset":0,"length":21,"style":"BOLD"}],"entityRanges":[],"data":{}},{"key":"7m4p9","text":"Fund contracts with any ERC-20 token.","type":"unordered-list-item","depth":0,"inlineStyleRanges":[{"offset":0,"length":37,"style":"BOLD"}],"entityRanges":[],"data":{}},{"key":"af4be","text":"Tokenization for funders & creators. When the creator withdraws ether, it mints tokens for all parties. These tokens can then be used for many things: voting, curation, special access, discounts and more. The creativity of the creator is the limit here.","type":"unordered-list-item","depth":0,"inlineStyleRanges":[{"offset":0,"length":35,"style":"BOLD"}],"entityRanges":[],"data":{}},{"key":"4ckb3","text":"Create funding buckets. For example fund many Ethereum dev related projects using a single payment.","type":"unordered-list-item","depth":0,"inlineStyleRanges":[{"offset":0,"length":22,"style":"BOLD"}],"entityRanges":[],"data":{}},{"key":"av3rs","text":"Build a platform. Make it easy for creators to communicate with and build their communities.","type":"unordered-list-item","depth":0,"inlineStyleRanges":[{"offset":0,"length":16,"style":"BOLD"}],"entityRanges":[],"data":{}},{"key":"22pbl","text":"Plus many more ideas to come! Check out the transparent roadmap here.","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[{"offset":44,"length":19,"key":1}],"data":{}},{"key":"cej54","text":"","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"bbip4","text":"But I need your help to build StakeTree.","type":"unstyled","depth":0,"inlineStyleRanges":[{"offset":0,"length":40,"style":"BOLD"}],"entityRanges":[],"data":{}},{"key":"bc51f","text":"","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"bjfag","text":"In true dogfooding fashion, I'll be building StakeTree using StakeTree itself.","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"26ufa","text":"","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"c33v5","text":"For updates, follow me on Twitter & Github.","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[{"offset":26,"length":7,"key":2},{"offset":36,"length":6,"key":3}],"data":{}}]} 6 | } -------------------------------------------------------------------------------- /data/effectivealtruism.json: -------------------------------------------------------------------------------- 1 | { 2 | "contractAddress": "0xd7506305f0d3e03a0b0c28fcf76d900497f75b75", 3 | "title": "Exploring the Overlap Between Effective Altruism + Blockchain", 4 | "avatar": "rhyslindmark.jpg", 5 | "description": {"entityMap":{"0":{"type":"LINK","mutability":"MUTABLE","data":{"href":"http://twitter.com/RhysLindmark","url":"http://twitter.com/RhysLindmark"}},"1":{"type":"LINK","mutability":"MUTABLE","data":{"href":"https://www.staketree.com/faq","url":"https://www.staketree.com/faq"}},"2":{"type":"LINK","mutability":"MUTABLE","data":{"href":"https://80000hours.org/articles/cause-selection/","url":"https://80000hours.org/articles/cause-selection/"}},"3":{"type":"LINK","mutability":"MUTABLE","data":{"href":"https://docs.google.com/document/d/1DoIj7U1M_Uu4AAo74B1WaJl1Y4QcqcCn3-XYZ3Yh_Q0/edit","url":"https://docs.google.com/document/d/1DoIj7U1M_Uu4AAo74B1WaJl1Y4QcqcCn3-XYZ3Yh_Q0/edit"}},"4":{"type":"LINK","mutability":"MUTABLE","data":{"href":"https://twitter.com/RhysLindmark","url":"https://twitter.com/RhysLindmark"}},"5":{"type":"LINK","mutability":"MUTABLE","data":{"href":"https://upscri.be/285036-2/","url":"https://upscri.be/285036-2/"}},"6":{"type":"LINK","mutability":"MUTABLE","data":{"href":"http://patreon.com/rhyslindmark","url":"http://patreon.com/rhyslindmark"}},"7":{"type":"LINK","mutability":"MUTABLE","data":{"href":"https://www.staketree.com/rhyslindmark","url":"https://www.staketree.com/rhyslindmark"}},"8":{"type":"LINK","mutability":"MUTABLE","data":{"href":"https://docs.google.com/document/d/1X8gz3R_731ThA7ggb-gGzqwHyvqpMeDqdjed3aF-_vs/edit","url":"https://docs.google.com/document/d/1X8gz3R_731ThA7ggb-gGzqwHyvqpMeDqdjed3aF-_vs/edit"}}},"blocks":[{"key":"tuaj","text":"Hey everyone!","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"1ir02","text":"","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"3tsh0","text":"I’m Rhys Lindmark and welcome to my StakeTree page! StakeTree allows supporters (like you!) to fund creators (like me!) with cryptocurrency. You stake (pledge) a certain amount of ETH, and I get to withdraw that stake over time. It’s like Patreon for Ethereum. ","type":"unstyled","depth":0,"inlineStyleRanges":[{"offset":4,"length":13,"style":"UNDERLINE"},{"offset":52,"length":9,"style":"UNDERLINE"}],"entityRanges":[{"offset":4,"length":13,"key":0},{"offset":52,"length":9,"key":1}],"data":{}},{"key":"d8nt","text":"","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"f7e9o","text":"The goal of this StakeTree is to explore the overlap between Effective Altruism and Blockchain. Right now this primarily involves two initiatives:","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"4sdmj","text":"","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"86n86","text":"Research to determine whether “positively shaping cryptocurrency/blockchain” should be a highly prioritized cause.","type":"unordered-list-item","depth":0,"inlineStyleRanges":[{"offset":89,"length":24,"style":"UNDERLINE"}],"entityRanges":[{"offset":89,"length":24,"key":2}],"data":{}},{"key":"1gnh","text":"Implementing and spreading a CryptoPledge—a commitment that people can take to give their cryptocurrency to effective causes.","type":"unordered-list-item","depth":0,"inlineStyleRanges":[{"offset":29,"length":12,"style":"UNDERLINE"}],"entityRanges":[{"offset":29,"length":12,"key":3}],"data":{}},{"key":"bugt3","text":"I’m hoping to spend 5 hours/week on this work, at $50/hour. (Though note that I allow 50% of funds to pass through me after $45,000/year.)","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"cr2af","text":"Essentially, support me if:","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"6seqg","text":"","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"2vo80","text":"You think more research should be done about shaping crypto for good","type":"unordered-list-item","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"9flma","text":"You think more people in crypto should give to effective charities","type":"unordered-list-item","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"dmkg8","text":"For updates, follow me on Twitter, subscribe to periodic email updates, check out my Patreon: Creating a Humanist Blockchain Future, or my ETHCommons StakeTree.","type":"unstyled","depth":0,"inlineStyleRanges":[{"offset":26,"length":7,"style":"UNDERLINE"},{"offset":35,"length":35,"style":"UNDERLINE"},{"offset":94,"length":37,"style":"UNDERLINE"},{"offset":139,"length":20,"style":"UNDERLINE"}],"entityRanges":[{"offset":26,"length":7,"key":4},{"offset":35,"length":35,"key":5},{"offset":94,"length":37,"key":6},{"offset":139,"length":20,"key":7}],"data":{}},{"key":"c3qij","text":"","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"2hp5l","text":"Thanks and please reach out to me at rhyslindmark [at] gmail [dot] com if you have questions!","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"8ahet","text":"- Rhys!","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"e8his","text":"","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"clivt","text":"(You can see a deeper exploration of my EA + Blockchain work here.)","type":"unstyled","depth":0,"inlineStyleRanges":[{"offset":61,"length":4,"style":"UNDERLINE"}],"entityRanges":[{"offset":61,"length":4,"key":8}],"data":{}}]} 6 | } -------------------------------------------------------------------------------- /data/rhyslindmark.json: -------------------------------------------------------------------------------- 1 | { 2 | "contractAddress": "0xef6bbc2662650d2d11b4e9910d2487e2630ca3e7", 3 | "title": "Co-Steward of the Ethereum Commons Co-op", 4 | "avatar": "rhyslindmark.jpg", 5 | "description": {"entityMap":{"0":{"type":"LINK","mutability":"MUTABLE","data":{"href":"http://twitter.com/RhysLindmark","url":"http://twitter.com/RhysLindmark"}},"1":{"type":"LINK","mutability":"MUTABLE","data":{"href":"https://www.staketree.com/faq","url":"https://www.staketree.com/faq"}},"2":{"type":"LINK","mutability":"MUTABLE","data":{"href":"https://medium.com/@RhysLindmark/co-evolving-the-phase-shift-to-cryptocapitalism-by-founding-the-ethereum-commons-co-op-f4771e5f0c83","url":"https://medium.com/@RhysLindmark/co-evolving-the-phase-shift-to-cryptocapitalism-by-founding-the-ethereum-commons-co-op-f4771e5f0c83"}},"3":{"type":"LINK","mutability":"MUTABLE","data":{"href":"https://twitter.com/RhysLindmark","url":"https://twitter.com/RhysLindmark"}},"4":{"type":"LINK","mutability":"MUTABLE","data":{"href":"https://upscri.be/285036-2/","url":"https://upscri.be/285036-2/"}},"5":{"type":"LINK","mutability":"MUTABLE","data":{"href":"http://patreon.com/rhyslindmark","url":"http://patreon.com/rhyslindmark"}}},"blocks":[{"key":"tuaj","text":"Hey everyone!","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"psf7","text":"","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"7vnkm","text":"I’m Rhys Lindmark and welcome to my StakeTree page! StakeTree allows supporters (like you!) to fund creators (like me!) with cryptocurrency. You stake (pledge) a certain amount of ETH, and I get to withdraw that stake over time. It’s like Patreon for Ethereum. ","type":"unstyled","depth":0,"inlineStyleRanges":[{"offset":4,"length":13,"style":"UNDERLINE"},{"offset":52,"length":9,"style":"UNDERLINE"}],"entityRanges":[{"offset":4,"length":13,"key":0},{"offset":52,"length":9,"key":1}],"data":{}},{"key":"ev94c","text":"","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"9f40n","text":"I’m Co-evolving the Phase Shift to Crypto Capitalism by Founding The Ethereum Commons Co-op. (If you don’t want the full context, just scroll to the bottom to see what I’m doing.)","type":"unstyled","depth":0,"inlineStyleRanges":[{"offset":4,"length":87,"style":"UNDERLINE"}],"entityRanges":[{"offset":4,"length":87,"key":2}],"data":{}},{"key":"f12ln","text":"","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"39jvu","text":"Essentially, support me if:","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"fomaj","text":"You’d like to transition to a world that internalizes externalities.","type":"unordered-list-item","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"8bg0c","text":"You think your specific Ethereum project could benefit from more collaboration. ","type":"unordered-list-item","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"ag9sd","text":"You think the world needs more people dedicated to co-evolving in the open-source commons.","type":"unordered-list-item","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"ehrsc","text":"For updates, follow me on Twitter, subscribe to periodic email updates, or check out my Patreon: Creating a Humanist Blockchain Future.","type":"unstyled","depth":0,"inlineStyleRanges":[{"offset":26,"length":7,"style":"UNDERLINE"},{"offset":35,"length":35,"style":"UNDERLINE"},{"offset":97,"length":37,"style":"UNDERLINE"}],"entityRanges":[{"offset":26,"length":7,"key":3},{"offset":35,"length":35,"key":4},{"offset":97,"length":37,"key":5}],"data":{}},{"key":"8lcbk","text":"","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"8aogc","text":"Thanks and please reach out to me at rhyslindmark [at] gmail [dot] com if you have questions!","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"cg2tf","text":"","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"3t30m","text":"- Rhys!","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}}]} 6 | } -------------------------------------------------------------------------------- /data/tokeneconomy.json: -------------------------------------------------------------------------------- 1 | { 2 | "contractAddress": "0x32085a2f89072cb55db465c42ed2680e4d8e7ac7", 3 | "title": "Token Economy", 4 | "avatar": "tecon.png", 5 | "description": {"blocks":[{"key":"tuaj","text":"Hello Token Economists 👋","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"84auu","text":"","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"8gkav","text":"Stefano and Yannick here, from your favourite crypto newsletter.","type":"unstyled","depth":0,"inlineStyleRanges":[{"offset":0,"length":7,"style":"UNDERLINE"},{"offset":12,"length":7,"style":"UNDERLINE"}],"entityRanges":[{"offset":0,"length":7,"key":0},{"offset":12,"length":7,"key":1}],"data":{}},{"key":"8248d","text":"","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"bo2t0","text":"We’ve been heads down running it since June 2017, and have been humbled by the positive feedback from many of you. Thanks, we very much want to keep up with it.","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"7fmd8","text":"","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"2dka5","text":"We never started with the end goal of turning it into a revenue-making business. Token Economy is first and foremost a platform to share, test-out and refine our views around what we feel are the most important developments in this nascent industry, while cultivating a network and community around it, learning along the way. ","type":"unstyled","depth":0,"inlineStyleRanges":[{"offset":117,"length":209,"style":"BOLD"}],"entityRanges":[],"data":{}},{"key":"doqln","text":"","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"fn1qi","text":"So far, other than our own time, it’s not been costing us very much to run it, frankly. However: ","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"93pm6","text":"","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"fb8jl","text":"we’re about to hit a higher pricing tier on our newsletter platform (a great problem to have!)","type":"unordered-list-item","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"6hr5p","text":"we’d love to grow and improve the content offering, launch new channels, get some help (e.g. a new logo, much needed!)","type":"unordered-list-item","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"c275f","text":"we are planning to sponsor/organize more events, conferences and meetups","type":"unordered-list-item","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"ehrbh","text":"we love dogfooding on cool projects when we can, and Niel’s Staketree is one of them","type":"unordered-list-item","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"493qo","text":"One cool thing about Staketree is that it will allow to tokenize the smart contract it runs on, which means that, if we ever decided to do that, funders could receive Token Economy tokens ($TEC?). Any ideas on what utility they could have? Let us know!","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"3l12b","text":"","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"6qk6j","text":"So here we go, feel free to contribute to this project in any way you feel appropriate. Staketree works such that we can only withdraw 10% of the funds per week, while you the funder can refund the balance of your funding at any time.","type":"unstyled","depth":0,"inlineStyleRanges":[{"offset":0,"length":87,"style":"BOLD"}],"entityRanges":[],"data":{}},{"key":"egulj","text":"","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"6k032","text":"🙏","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"8kh78","text":"","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"c3lb5","text":"Stefano & Yannick","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"cf519","text":"","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}},{"key":"ebocn","text":"📨 subscribe at weekly.tokeneconomy.co","type":"unstyled","depth":0,"inlineStyleRanges":[{"offset":15,"length":22,"style":"UNDERLINE"}],"entityRanges":[{"offset":15,"length":22,"key":2}],"data":{}}],"entityMap":{"0":{"type":"LINK","mutability":"MUTABLE","data":{"href":"https://twitter.com/stefanobernardi","url":"https://twitter.com/stefanobernardi"}},"1":{"type":"LINK","mutability":"MUTABLE","data":{"href":"https://twitter.com/yanroux","url":"https://twitter.com/yanroux"}},"2":{"type":"LINK","mutability":"MUTABLE","data":{"href":"http://weekly.tokeneconomy.co/","url":"http://weekly.tokeneconomy.co/"}}}} 6 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "staketreesite", 3 | "version": "0.1.0", 4 | "private": true, 5 | "engines": { 6 | "node": "7.10.1" 7 | }, 8 | "dependencies": { 9 | "draft-js": "^0.10.4", 10 | "draft-js-anchor-plugin": "^2.0.1", 11 | "draft-js-plugins-editor": "^2.0.3", 12 | "draft-js-static-toolbar-plugin": "^2.0.1", 13 | "express": "^4.15.4", 14 | "ipfs-api": "^17.2.4", 15 | "lodash": "^4.17.4", 16 | "react": "^15.6.1", 17 | "react-dom": "^15.6.1", 18 | "react-modal": "^3.1.0", 19 | "react-router-dom": "^4.2.2", 20 | "react-router-hash-link": "^1.1.1", 21 | "react-scripts": "1.0.13", 22 | "staketree-contracts": "0.0.7", 23 | "truffle-contract": "^3.0.0", 24 | "web3": "^1.0.0-beta.20" 25 | }, 26 | "scripts": { 27 | "dev": "react-scripts start", 28 | "start": "node server.js", 29 | "build": "react-scripts build", 30 | "test": "react-scripts test --env=jsdom", 31 | "eject": "react-scripts eject", 32 | "heroku-postbuild": "mkdir build && npm run build" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StakeTree/site/5a4ece37fa0811853d8a877bcc59bc2d65d4ce6e/public/favicon.ico -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | 13 | 22 | 23 | 34 | 35 | StakeTree 36 | 37 | 38 | 41 |
42 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "StakeTree App", 3 | "name": "StakeTree Site App", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | } 10 | ], 11 | "start_url": "./index.html", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /public/niel.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StakeTree/site/5a4ece37fa0811853d8a877bcc59bc2d65d4ce6e/public/niel.jpg -------------------------------------------------------------------------------- /public/rhyslindmark.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StakeTree/site/5a4ece37fa0811853d8a877bcc59bc2d65d4ce6e/public/rhyslindmark.jpg -------------------------------------------------------------------------------- /public/tecon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StakeTree/site/5a4ece37fa0811853d8a877bcc59bc2d65d4ce6e/public/tecon.png -------------------------------------------------------------------------------- /scripts/publishToIPFS.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const path = require('path'); 3 | const ipfsAPI = require('ipfs-api'); 4 | const ipfs = ipfsAPI({host: 'ipfs.infura.io', port: '5001', protocol: 'https'}); 5 | 6 | fs.readFile(path.resolve('./data/tokeneconomy.json'), (err, res)=>{ 7 | ipfs.files.add([{path: 'tokeneconomy.json', content: res}], function (err, files) { 8 | console.log(err, files); 9 | // 'files' will be an array of objects containing paths and the multihashes of the files added 10 | }); 11 | }); -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const path = require('path'); 3 | const app = express(); 4 | const Web3 = require('web3'); 5 | const TruffleContract = require('truffle-contract'); 6 | const StakeTreeWithTokenization = require('staketree-contracts/build/contracts/StakeTreeWithTokenization.json'); 7 | 8 | const isLocal = process.env.PORT ? false : true; 9 | let web3; 10 | if(isLocal){ 11 | web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545")); 12 | } 13 | else { 14 | web3 = new Web3(new Web3.providers.HttpProvider("https://mainnet.infura.io")); 15 | } 16 | 17 | 18 | if(isLocal){ 19 | 20 | // Allow CORS for testing locally 21 | app.all('/*', function(req, res, next) { 22 | res.header("Access-Control-Allow-Origin", "*"); 23 | res.header("Access-Control-Allow-Headers", "X-Requested-With"); 24 | next(); 25 | }); 26 | } 27 | 28 | app.use(express.static(path.join(__dirname, 'build'))); 29 | 30 | app.get('/contract/:address', async (req, res, next) => { 31 | const contract = TruffleContract(StakeTreeWithTokenization); 32 | contract.setProvider(web3.currentProvider); 33 | 34 | // dirty hack for web3@1.0.0 support for localhost testrpc, 35 | // see https://github.com/trufflesuite/truffle-contract/issues/56#issuecomment-331084530 36 | if (typeof contract.currentProvider.sendAsync !== "function") { 37 | contract.currentProvider.sendAsync = function() { 38 | return contract.currentProvider.send.apply( 39 | contract.currentProvider, 40 | arguments 41 | ); 42 | }; 43 | } 44 | 45 | // TODO: Validate address 46 | 47 | const instance = await contract.at(req.params.address); 48 | const balance = await instance.getContractBalance.call(); 49 | const totalCurrentFunders = await instance.getCurrentTotalFunders.call(); 50 | const contractStartTime = await instance.contractStartTime.call(); 51 | const nextWithdrawal = await instance.nextWithdrawal.call(); 52 | const withdrawalPeriod = await instance.withdrawalPeriod.call(); 53 | 54 | const live = await instance.live.call(); 55 | const sunsetPeriod = await instance.sunsetWithdrawalPeriod.call(); 56 | const minimumFundingAmount = await instance.minimumFundingAmount.call(); 57 | const tokenized = await instance.tokenized.call(); 58 | const withdrawalCounter = await instance.withdrawalCounter.call(); 59 | 60 | res.json({ 61 | "balance": balance, 62 | "totalCurrentFunders": totalCurrentFunders, 63 | "contractStartTime": contractStartTime, 64 | "nextWithdrawal": nextWithdrawal, 65 | "withdrawalPeriod": withdrawalPeriod, 66 | "live": live, 67 | "sunsetPeriod": sunsetPeriod, 68 | "minimumFundingAmount": minimumFundingAmount, 69 | "tokenized": tokenized, 70 | "withdrawalCounter": withdrawalCounter 71 | }); 72 | 73 | }); 74 | 75 | app.get('*', function (req, res) { 76 | res.sendFile(path.join(__dirname, 'build', 'index.html')); 77 | }); 78 | 79 | 80 | const port = process.env.PORT || 3000; 81 | 82 | app.listen(port); -------------------------------------------------------------------------------- /src/AddTokensButton.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import Modal from 'react-modal'; 3 | 4 | import { HashLink as Link } from 'react-router-hash-link'; 5 | 6 | import web3store from "./Web3Store.js"; 7 | 8 | class AddTokensButton extends Component { 9 | constructor(props) { 10 | super(props); 11 | this.state = { 12 | showModal: false, 13 | showModalForm: false, 14 | tokenName: '', 15 | tokenSymbol: '', 16 | tokenDecimals: 18, 17 | disabledTokenButton: true 18 | }; 19 | } 20 | showModal() { 21 | this.setState({showModal: true}); 22 | } 23 | closeModal() { 24 | this.setState({showModal: false}); 25 | } 26 | showModalForm() { 27 | this.closeModal(); 28 | this.setState({showModalForm: true}); 29 | } 30 | closeModalForm(){ 31 | this.setState({showModalForm: false}); 32 | } 33 | addTokenization(e) { 34 | window.web3.eth.getAccounts(async (error, accounts) => { 35 | this.props.contract.addTokenization( 36 | this.state.tokenName, 37 | this.state.tokenSymbol, 38 | this.state.tokenDecimals, 39 | {"from": accounts[0], gas: 3200000, gasPrice: window.web3.toWei(1, 'gwei')}, (err, txHash)=>{ 40 | if(!err) { 41 | this.closeModalForm(); 42 | web3store.addTransaction({type: 'add-tokens', hash: txHash, mined: false}); 43 | } 44 | }); 45 | }); 46 | } 47 | handleTokenName(e) { 48 | this.setState({tokenName: e.target.value}); 49 | setTimeout(this.validateTokenDetails.bind(this), 10); 50 | } 51 | handleTokenSymbol(e) { 52 | const value = e.target.value.substring(0,5); 53 | this.setState({tokenSymbol: value}); 54 | setTimeout(this.validateTokenDetails.bind(this), 10); 55 | } 56 | handleTokenDecimals(e) { 57 | this.setState({tokenDecimals: e.target.value}); 58 | setTimeout(this.validateTokenDetails.bind(this), 10); 59 | } 60 | 61 | validateTokenDetails() { 62 | if(this.state.tokenName.length === 0) return this.setState({disabledTokenButton: true}); 63 | if(this.state.tokenSymbol.length === 0) return this.setState({disabledTokenButton: true}); 64 | if(this.state.tokenDecimals > 18) return this.setState({disabledTokenButton: true}); 65 | 66 | this.setState({disabledTokenButton: false}); 67 | } 68 | render() { 69 | let addTokenizationButtonClassNames = "btn"; 70 | if(this.state.disabledTokenButton) addTokenizationButtonClassNames += " disabled-btn"; 71 | let buttonHtml = this.props.visible ? 72 | 81 |

Are you sure?

82 |

When you add tokenization to your contract you won't be able to reverse this.

83 |

Unsure about what this means? Read more here first.

84 | 85 | 86 |
87 | 88 | 97 |

Token details

98 |
99 |

Fill in the details of your token. These details can't be changed 100 | once you added tokenization to your contract.

101 |

Unsure of what these mean? Read more here first

102 | 103 | 108 | 109 | 110 | 115 | 116 | 117 | 122 |
123 | 124 | 125 | 126 |

Note: this transaction might take a while to be confirmed.

127 |
128 | 129 | 130 |
: ; 131 | return buttonHtml; 132 | } 133 | 134 | }; 135 | 136 | export default AddTokensButton; -------------------------------------------------------------------------------- /src/App.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { BrowserRouter as Router, Route, Switch } from 'react-router-dom'; 3 | import './skeleton.css'; 4 | import './font-awesome/css/font-awesome.css'; 5 | 6 | import Home from './Home.js'; 7 | import CreatorPage from './CreatorPage.js'; 8 | import ContractInterface from './ContractInterface.js'; 9 | import Deploy from './Deploy.js'; 10 | 11 | import Nav from './Nav.js'; 12 | 13 | import FAQ from './FAQ.js'; 14 | 15 | class App extends Component { 16 | render() { 17 | return ( 18 | 19 |
20 |
29 |
30 | ); 31 | } 32 | } 33 | 34 | export default App; 35 | -------------------------------------------------------------------------------- /src/App.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './App'; 4 | 5 | it('renders without crashing', () => { 6 | const div = document.createElement('div'); 7 | ReactDOM.render(, div); 8 | }); 9 | -------------------------------------------------------------------------------- /src/BeneficiaryCard.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | 3 | import WithdrawButton from './WithdrawButton.js'; 4 | import AddTokensButton from './AddTokensButton.js'; 5 | import SetMinAmountButton from './SetMinAmountButton.js'; 6 | 7 | import './ContractCard.css'; 8 | 9 | class BeneficiaryCard extends Component { 10 | constructor(props) { 11 | super(props); 12 | 13 | this.state = { 14 | newMinAmount: this.props.minAmount, 15 | showMinAmountOptions: false 16 | }; 17 | } 18 | handleCustomAmount(e) { 19 | let value = e.target.value; 20 | this.setState({newMinAmount: value}); 21 | } 22 | toggleSetMinAmountOptions() { 23 | this.setState({showMinAmountOptions: !this.state.showMinAmountOptions}); 24 | } 25 | render() { 26 | return ( 27 |
28 |
29 |

Hi there beneficiary,

30 |
    31 |
  • Total $ staked: ±${this.props.totalStakedDollar}
  • 32 |
  • Total withdrawals: {this.props.withdrawalCounter}
  • 33 |
34 |
35 | Withdraw 39 |
40 | 41 | {this.state.showMinAmountOptions ? 42 |
43 | 44 | Set minimum funding amount 49 |
50 | : 51 | ''} 52 | 53 | {!this.props.tokenized ? 54 | Add Tokenization 58 | : ''} 59 |
60 |
61 |
62 | ) 63 | } 64 | }; 65 | 66 | export default BeneficiaryCard; -------------------------------------------------------------------------------- /src/ClaimTokensButton.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | 3 | import web3store from "./Web3Store.js"; 4 | 5 | class ClaimTokensButton extends Component { 6 | constructor(props) { 7 | super(props); 8 | this.state = { 9 | showTooltip: false 10 | } 11 | } 12 | showTooltip() { 13 | if(this.props.claimAmount <= 0) { 14 | this.setState({showTooltip: true}); 15 | } 16 | } 17 | hideTooltip() { 18 | this.setState({showTooltip: false}); 19 | } 20 | claimTokens() { 21 | if(this.props.claimAmount <= 0) { 22 | return false; 23 | } 24 | 25 | window.web3.eth.getAccounts(async (error, accounts) => { 26 | this.props.contract.claimTokens({"from": accounts[0], "gas": 150000}, (err, txHash)=>{ 27 | if(!err) { 28 | web3store.addTransaction({type: 'claim_tokens', hash: txHash, mined: false}); 29 | } 30 | }); 31 | }); 32 | } 33 | render() { 34 | let tooltipClassNames = "tooltip"; 35 | if(this.state.showTooltip) tooltipClassNames += ' visible'; 36 | 37 | let buttonHtml = this.props.visible ? 38 |
{`You don't have any tokens to claim.`}
39 | 40 |
: ; 41 | 42 | return buttonHtml; 43 | } 44 | }; 45 | 46 | export default ClaimTokensButton; -------------------------------------------------------------------------------- /src/ContractCard.css: -------------------------------------------------------------------------------- 1 | .more-options{ 2 | border-left: 1px solid #eee; 3 | box-sizing: border-box; 4 | padding: 10%; 5 | border-right: 1px solid #eee; 6 | margin-top: -15px; 7 | background-color: #fcfcfc; 8 | margin-bottom: -10px; 9 | } -------------------------------------------------------------------------------- /src/ContractInterface.css: -------------------------------------------------------------------------------- 1 | .contract-card { 2 | border: 1px solid #eee; 3 | width: 100%; 4 | padding: 24px; 5 | border-radius: 4px; 6 | margin: 8px; 7 | margin-top: 30px; 8 | box-shadow: 0px 2px 2px #ccc; 9 | box-sizing: border-box; 10 | } 11 | 12 | .contract-card h4 { 13 | font-size: 2.5rem; 14 | margin: 8px 0px; 15 | } 16 | 17 | .contract-card li { 18 | margin: 0px; 19 | list-style: none; 20 | } 21 | 22 | .contract-card .custom-value-input { 23 | width: 100%; 24 | } 25 | 26 | .contract-card-actions .btn { 27 | margin-right: 4px; 28 | } 29 | 30 | .contract-card-actions .main-actions { 31 | border-bottom: 1px solid #ddd; 32 | padding-bottom: 8px; 33 | margin-bottom: 16px; 34 | } 35 | 36 | .contract-card-actions .token-action { 37 | padding-bottom: 8px; 38 | margin-bottom: 8px; 39 | } -------------------------------------------------------------------------------- /src/ContractInterface.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import Web3 from 'web3'; // TODO: follow up on how to use web3 when pulled in vs metamask 3 | 4 | // Styling 5 | import './ContractInterface.css'; 6 | 7 | // Other 8 | import Web3Controller from './Web3Controller.js'; 9 | import web3store from './Web3Store.js'; 10 | 11 | //Components 12 | import FundButton from './FundButton.js'; 13 | import EtherscanLink from './EtherscanLink.js'; 14 | import FunderCard from './FunderCard.js'; 15 | import BeneficiaryCard from './BeneficiaryCard.js'; 16 | 17 | let web3Polling; 18 | const web3 = new Web3(); 19 | 20 | class ContractInterface extends Component { 21 | constructor(props) { 22 | super(props); 23 | 24 | this.state = { 25 | exchangeRate: 0, 26 | currentEthAccount: "0x0000000000000000000000000000000000000000", 27 | showTooltip: "", 28 | isFunder: false, 29 | isBeneficiary: false, 30 | customAmount: 0.1, 31 | web3available: true, 32 | contractAddress: this.props.match.params.address, 33 | contract: { 34 | totalCurrentFunders: 0, 35 | balance: 0, 36 | startTime: "...", 37 | nextWithdrawal: "...", 38 | withdrawalPeriod: "...", 39 | live: true, 40 | sunsetPeriod: "...", 41 | minimumFundingAmount: 0, 42 | tokenContract: "0x0000000000000000000000000000000000000000", 43 | withdrawalCounter: 0 44 | }, 45 | contractInstance: '', 46 | loading: true, 47 | user: { // Fetch this information in the future 48 | title: 'StakeTree Development Fund', 49 | } 50 | }; 51 | } 52 | 53 | async componentWillMount() { 54 | fetch("https://api.coinmarketcap.com/v1/ticker/ethereum/?convert=USD") 55 | .then(res => {return res.json()}) 56 | .then(data => { 57 | this.setState({ 58 | exchangeRate: parseInt(data[0].price_usd, 10) 59 | }); 60 | }); 61 | 62 | // Poll web3 availability 63 | if(typeof window.web3 !== 'undefined') { 64 | this.hydrate(); 65 | } 66 | else{ 67 | let pollingCounter = 0; 68 | web3Polling = setInterval(async ()=> { 69 | if(typeof window.web3 !== 'undefined') { 70 | clearInterval(web3Polling); 71 | this.setState({"web3available": true}); 72 | this.hydrate(); 73 | } 74 | else { 75 | pollingCounter++; 76 | if(pollingCounter === 3) { 77 | this.setState({loading: false, web3available: false}); 78 | } 79 | } 80 | }, 1500); 81 | } 82 | } 83 | 84 | componentWillUnmount() { 85 | clearInterval(web3Polling); 86 | web3store.unsubscribe('contract-dashboard'); 87 | Web3Controller.unsubscribeFromAccountChange(); 88 | } 89 | 90 | async hydrate() { 91 | const instance = Web3Controller.newInstance({ 92 | which: "StakeTreeWithTokenization", 93 | at: this.state.contractAddress 94 | }); 95 | 96 | // Verify contract 97 | instance.version.call({}, async (err, result)=>{ 98 | if(result && result.c && result.c[0] && result.c[0] === 2) { 99 | this.setState({contractInstance: instance}); 100 | this.setState({loading: false}); 101 | 102 | Web3Controller.getCurrentAccount((currentAccount)=>{ 103 | this.setState({currentEthAccount: currentAccount}); 104 | this.getContractDetails(); 105 | 106 | // All set, now lets poll for values we are looking for 107 | Web3Controller.subscribeToAccountChange((newAccount) => { 108 | this.setState({ 109 | currentEthAccount: newAccount, 110 | isFunder: false, 111 | isBeneficiary: false 112 | }); 113 | this.getContractDetails(); 114 | }); 115 | }); 116 | 117 | web3store.subscribe('contract-dashboard', (newState)=>{ 118 | setTimeout(()=>{this.getContractDetails()}, 5000); 119 | }); 120 | } 121 | else { 122 | // No contract found 123 | this.setState({loading: false}); 124 | } 125 | }); 126 | } 127 | 128 | getContractDetails() { 129 | Web3Controller.getContractDetails({ 130 | id: 'main-contract-details', 131 | instance: this.state.contractInstance, 132 | variables: [ 133 | 'totalCurrentFunders', 'contractStartTime', 'beneficiary', 'getContractBalance', 134 | 'nextWithdrawal', 'withdrawalPeriod', 'live', 'sunsetWithdrawalPeriod', 135 | 'minimumFundingAmount', 'tokenized', 'withdrawalCounter', 'tokenContract' 136 | ] 137 | }, (key, value) => { 138 | if(key === "getContractBalance") key = "balance"; 139 | this.setContractState(key, value); 140 | }); 141 | 142 | Web3Controller.getContractDetails({ 143 | id: 'is-funder', 144 | instance: this.state.contractInstance, 145 | functions: [ 146 | {name: 'isFunder', arg: this.state.currentEthAccount} 147 | ] 148 | }, (key, isFunder) => { 149 | this.setState({ 150 | ...this.state, 151 | isFunder: isFunder, 152 | }); 153 | }); 154 | 155 | Web3Controller.getContractDetails({ 156 | id: 'is-beneficiary', 157 | instance: this.state.contractInstance, 158 | variables: ['beneficiary'] 159 | }, (key, beneficiary) => { 160 | this.setState({ 161 | ...this.state, 162 | isBeneficiary: this.state.currentEthAccount === beneficiary, 163 | }); 164 | }); 165 | } 166 | 167 | setContractState(key, value) { 168 | const newContractState = { 169 | ...this.state.contract 170 | }; 171 | newContractState[key] = value; 172 | 173 | this.setState({ 174 | contract: newContractState 175 | }); 176 | } 177 | 178 | handleCustomAmount(e) { 179 | let value = e.target.value; 180 | if(e.target.value === "") value = 0.1; 181 | this.setState({customAmount: value}); 182 | } 183 | 184 | noWeb3() { 185 | if(!this.state.web3available) { 186 | return

To fund StakeTree using the buttons below you need have MetaMask installed. If you have MetaMask installed, try unlocking it before trying again. Otherwise send ether to this address, {this.state.contractAddress}, using your preffered wallet.

; 187 | } 188 | return ""; 189 | } 190 | 191 | 192 | render() { 193 | 194 | const customAmount = this.state.customAmount > 0 ? this.state.customAmount : 0.1; 195 | 196 | const fundStarted = new Date(this.state.contract.contractStartTime*1000).toLocaleDateString(); 197 | const nextWithdrawal = new Date(this.state.contract.nextWithdrawal*1000).toLocaleDateString(); 198 | const sunsetPeriodDays = Math.floor((this.state.contract.sunsetWithdrawalPeriod % 31536000) / 86400); 199 | const withdrawalPeriodDays = Math.floor((this.state.contract.withdrawalPeriod % 31536000) / 86400); 200 | 201 | const balance = web3.utils.fromWei(String(this.state.contract.balance), 'ether'); 202 | 203 | let withdrawalAmount = this.state.exchangeRate * (balance * 0.1); 204 | withdrawalAmount = withdrawalAmount.toFixed(2); 205 | 206 | let totalStakedDollar = this.state.exchangeRate * (balance); 207 | totalStakedDollar = totalStakedDollar.toFixed(2); 208 | 209 | const minAmount = web3.utils.fromWei(String(this.state.contract.minimumFundingAmount), 'ether'); 210 | 211 | const noContractHtml = this.state.web3available && this.state.contractInstance === '' ?
212 |
213 |

No staketree contract found at this address. Double check that you have the correct address.

214 |
215 |
: ; 216 | 217 | const noWeb3 = !this.state.web3available ?
218 |
219 |

It doesn't seem like you have MetaMask installed. Try installing it and refreshing this page.

220 |
221 |
: ; 222 | 223 | return ( 224 |
225 |
226 | {this.state.loading ? 227 |
228 | Loading... 229 |
230 | : 231 | 232 | {noWeb3} 233 | {noContractHtml} 234 | {this.state.contractInstance ? 235 | 236 |
237 | {this.state.isFunder ? : ''} 244 | {this.state.isBeneficiary ? : ''} 251 | {!this.state.isBeneficiary && !this.state.isFunder ?
252 | Are you a beneficiary or funder? Select your respective account in Metamask to interact with this contract. 253 |
: ''} 254 |
255 | 256 |
257 |
258 |

Contract details

259 |
    260 |
  • Total staked: {balance} ether
  • 261 |
  • Total funders: {this.state.contract.totalCurrentFunders}
  • 262 |
  • Next Withdrawal Amount: ±${withdrawalAmount}
  • 263 |
  • Withdrawal Period: {withdrawalPeriodDays} days
  • 264 |
  • Next Withdrawal: {nextWithdrawal}
  • 265 |
  • Fund Started: {fundStarted}
  • 266 |
  • Sunset Period: {sunsetPeriodDays} days
  • 267 |
  • Live: {this.state.contract.live ? '✔' : '🚫'}
  • 268 |
  • Beneficiary:
  • 269 |
  • Contract:
  • 270 |
271 |
272 |
273 | Stake {customAmount} Ether 274 | 275 |
276 |
277 |
278 |
: ''} 279 |
280 | } 281 |
282 |
283 | ); 284 | } 285 | } 286 | 287 | export default ContractInterface; -------------------------------------------------------------------------------- /src/CreatorPage.css: -------------------------------------------------------------------------------- 1 | .creatorpage-highlights { 2 | margin-top: 20px; 3 | } 4 | .featurette.creatorpage-highlight { 5 | border: 1px solid #ddd; 6 | border-radius: 5px; 7 | /*background-color: #efefef;*/ 8 | box-shadow: inset 0px 0px 10px #efefef; 9 | padding: 10px 0px 0px 0px; 10 | height: 40px; 11 | margin-top: 10px; 12 | } 13 | .sidebar { 14 | position: relative; 15 | } 16 | 17 | .sidebar .btn { 18 | width: 100%; 19 | } 20 | 21 | .sidebar input[type="number"] { 22 | width: 100%; 23 | } 24 | .creatorpage-avatar { 25 | display: inline-block; 26 | padding-left: 10%; 27 | } 28 | .creatorpage-avatar img{ 29 | float: left; 30 | border-radius: 5px; 31 | width: 90%; 32 | margin: 2px 20px 10px 0px; 33 | } 34 | 35 | .creatorpage-project-name { 36 | margin-top: 14px; 37 | } 38 | 39 | .sidebar-key-info-heading { 40 | font-size: 2rem; 41 | border-bottom: 1px solid #ddd; 42 | margin-bottom: 10px; 43 | } 44 | 45 | .sidebar-key-info { 46 | padding-bottom: 10px; 47 | margin-bottom: 10px; 48 | border-bottom: 1px solid #ddd; 49 | } 50 | 51 | .sidebar-other-info { 52 | font-size: 1rem; 53 | padding-bottom: 10px; 54 | border-bottom: 1px solid #ddd; 55 | } 56 | 57 | .sidebar-actions { 58 | position: relative; 59 | } 60 | 61 | .creator-page .contract-card { 62 | width: initial; 63 | margin: 0px; 64 | margin-top: 16px; 65 | } 66 | 67 | .creator-page .min-amount-btn { 68 | font-size: .9rem; 69 | } 70 | 71 | .creator-page .more-options .min-amount-btn { 72 | padding-left: 16px; 73 | font-size: 0.8rem; 74 | } -------------------------------------------------------------------------------- /src/CreatorPage.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import Web3 from 'web3'; // TODO: follow up on how to use web3 when pulled in vs metamask 3 | import { Link } from 'react-router-dom'; 4 | 5 | import Creators from './creatorsToIPFSMap.json'; 6 | 7 | // Styling 8 | import './CreatorPage.css'; 9 | 10 | // Other 11 | import Web3Controller from './Web3Controller.js'; 12 | import web3store from './Web3Store.js'; 13 | 14 | //Components 15 | import EtherscanLink from './EtherscanLink.js'; 16 | import FundButton from './FundButton.js'; 17 | import PageEditor from './PageEditor.js'; 18 | 19 | let web3Polling; 20 | const web3 = new Web3(); 21 | 22 | class CreatorPage extends Component { 23 | constructor(props) { 24 | super(props); 25 | 26 | this.state = { 27 | isEditing: false, 28 | userLoading: true, 29 | contractLoading: true, 30 | exchangeRate: 0, 31 | currentEthAccount: "0x0000000000000000000000000000000000000000", 32 | showTooltip: "", 33 | isFunder: false, 34 | isBeneficiary: false, 35 | customAmount: 0.1, 36 | web3available: false, 37 | // contractAddress: "0x8c79ec3f260b067157b0a7db0bb465f90b87f8f1", 38 | // contractAddress: "0x34ef16c1f5f864a6b8de05205966b53e9fb0aaca", // Rinkeby test contract 39 | // contractAddress: "0x4ca3e0f44aacb3b0cc68e76a6cb94cb19afc3307", // local 40 | contract: { 41 | totalCurrentFunders: 0, 42 | balance: 0, 43 | startTime: "...", 44 | nextWithdrawal: "...", 45 | withdrawalPeriod: "...", 46 | live: true, 47 | sunsetWithdrawalPeriod: "...", 48 | minimumFundingAmount: 0, 49 | tokenContract: "0x0000000000000000000000000000000000000000" 50 | }, 51 | contractInstance: '', 52 | creator: {title: ''} 53 | }; 54 | 55 | window.CreatorPage = this; 56 | } 57 | 58 | fetchCreator(creatorUrl) { 59 | if(typeof Creators[creatorUrl] !== 'undefined'){ 60 | const ipfsHash = Creators[creatorUrl]; 61 | fetch(`https://ipfs.infura.io/ipfs/${ipfsHash}`) 62 | .then((res) => {return res.json()}) 63 | .then(data => { 64 | this.setState({creator: data}); 65 | this.setState({userLoading: false}); 66 | 67 | // TODO: serve -s build runs this on port 5000 68 | const fetchHost = window.location.hostname === "localhost" ? "http://localhost:3000" : ''; 69 | const fetchUrl = `${fetchHost}/contract/${this.state.creator.contractAddress}`; 70 | // TODO: Polyfill fetch for back suport 71 | fetch(fetchUrl) 72 | .then((res) => {return res.json()}) 73 | .then(data => { 74 | this.setState({ 75 | ...this.state, 76 | contract: data 77 | }); 78 | }); 79 | 80 | if(typeof window.web3 !== 'undefined') { 81 | this.hydrate(); 82 | } 83 | else { 84 | // Poll for web3 availability 85 | web3Polling = setInterval(async ()=> { 86 | if(typeof window.web3 !== 'undefined') { 87 | clearInterval(web3Polling); 88 | this.setState({"web3available": true}); 89 | this.hydrate(); 90 | } 91 | }, 1500); 92 | } 93 | }); 94 | } 95 | else { 96 | // NO USER 97 | console.log("NO USER AT THIS ADDESS"); 98 | } 99 | } 100 | 101 | componentWillReceiveProps(nextProps) { 102 | // We've changed to a new creator page. Let's refetch things 103 | if(nextProps.match.url !== this.props.match.url) { 104 | this.setState({userLoading: true}); 105 | this.setState({contractLoading: true}); 106 | 107 | this.fetchCreator(nextProps.match.url); 108 | } 109 | } 110 | 111 | async componentWillMount() { 112 | fetch("https://api.coinmarketcap.com/v1/ticker/ethereum/?convert=USD") 113 | .then(res => {return res.json()}) 114 | .then(data => { 115 | this.setState({ 116 | exchangeRate: parseInt(data[0].price_usd, 10) 117 | }); 118 | }); 119 | this.fetchCreator(this.props.match.url); 120 | } 121 | 122 | async hydrate() { 123 | const instance = Web3Controller.newInstance({ 124 | which: "StakeTreeWithTokenization", 125 | at: this.state.creator.contractAddress 126 | }); 127 | 128 | // Verify contract 129 | instance.version.call({}, async (err, result)=>{ 130 | if(result && result.c && result.c[0] && result.c[0] === 2) { 131 | this.setState({contractInstance: instance}); 132 | this.setState({contractLoading: false}); 133 | 134 | Web3Controller.getCurrentAccount((currentAccount)=>{ 135 | this.setState({currentEthAccount: currentAccount}); 136 | this.getContractDetails(); 137 | 138 | // All set, now lets poll for values we are looking for 139 | Web3Controller.subscribeToAccountChange((newAccount) => { 140 | this.setState({ 141 | currentEthAccount: newAccount, 142 | isFunder: false, 143 | isBeneficiary: false 144 | }); 145 | this.getContractDetails(); 146 | }); 147 | }); 148 | 149 | web3store.subscribe('creator-page', (newState)=>{ 150 | setTimeout(()=>{this.getContractDetails()}, 5000); 151 | }); 152 | } 153 | else { 154 | // No contract found 155 | this.setState({contractLoading: false}); 156 | } 157 | }); 158 | } 159 | 160 | getContractDetails() { 161 | Web3Controller.getContractDetails({ 162 | id: 'main-contract-details', 163 | instance: this.state.contractInstance, 164 | variables: [ 165 | 'totalCurrentFunders', 'contractStartTime', 'beneficiary', 'getContractBalance', 166 | 'nextWithdrawal', 'withdrawalPeriod', 'live', 'sunsetWithdrawalPeriod', 167 | 'minimumFundingAmount', 'tokenized', 'withdrawalCounter', 'tokenContract' 168 | ], 169 | }, (key, value) => { 170 | if(key === "getContractBalance") key = "balance"; 171 | this.setContractState(key, value); 172 | }); 173 | } 174 | 175 | setContractState(key, value) { 176 | const newContractState = { 177 | ...this.state.contract 178 | }; 179 | newContractState[key] = value; 180 | 181 | this.setState({ 182 | contract: newContractState 183 | }); 184 | } 185 | 186 | componentWillUnmount() { 187 | clearInterval(web3Polling); 188 | web3store.unsubscribe('creator-page'); 189 | Web3Controller.unsubscribeFromAccountChange(); 190 | } 191 | 192 | handleCustomAmount(e) { 193 | let value = e.target.value; 194 | if(e.target.value === "") value = 0.1; 195 | this.setState({customAmount: value}); 196 | } 197 | 198 | render() { 199 | 200 | const customAmount = this.state.customAmount > 0 ? this.state.customAmount : 0.1; 201 | 202 | const fundStarted = new Date(this.state.contract.contractStartTime*1000).toLocaleDateString(); 203 | const nextWithdrawal = new Date(this.state.contract.nextWithdrawal*1000).toLocaleDateString(); 204 | const sunsetPeriodDays = Math.floor((this.state.contract.sunsetWithdrawalPeriod % 31536000) / 86400); 205 | const withdrawalPeriodDays = Math.floor((this.state.contract.withdrawalPeriod % 31536000) / 86400); 206 | 207 | const balance = web3.utils.fromWei(String(this.state.contract.balance), 'ether'); 208 | 209 | let withdrawalAmount = this.state.exchangeRate * (balance * 0.1); 210 | withdrawalAmount = withdrawalAmount.toFixed(2); 211 | 212 | const minAmount = web3.utils.fromWei(String(this.state.contract.minimumFundingAmount), 'ether'); 213 | 214 | return ( 215 |
216 | {this.state.userLoading ? 'Loading...' : 217 | 218 |
219 |
220 |

{this.state.creator.title}

221 |
222 |
223 | 224 |
225 |
226 |
227 | {`Avatar 228 | Stake {customAmount} Ether 229 | 230 |
231 |
Fund Details
232 | Next withdrawal amount: ±${withdrawalAmount}
233 | Total contributors: {this.state.contract.totalCurrentFunders}
234 | Total staked: {balance} ether
235 | Next withdrawal: {nextWithdrawal} 236 |
237 |
238 | Live: {this.state.contract.live ? '✅' : '🚫'}
239 | Fund started: {fundStarted}
240 | Withdrawal period: {withdrawalPeriodDays} days
241 | Sunset Period: {sunsetPeriodDays} days
242 | Contract Source: 243 |
244 |
245 | 246 |
247 | Are you a beneficiary or funder? Head to the contract dashboard to interact with this contract. 248 |
249 |
250 |
251 | 252 |
253 |
254 | 255 |
256 | } 257 |
258 | ); 259 | } 260 | } 261 | 262 | export default CreatorPage; 263 | -------------------------------------------------------------------------------- /src/Deploy.css: -------------------------------------------------------------------------------- 1 | .deploy-input { 2 | width: 100%; 3 | } 4 | 5 | .address-info { 6 | 7 | } -------------------------------------------------------------------------------- /src/Deploy.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import TruffleContract from 'truffle-contract'; 3 | import StakeTreeWithTokenizationFactory from 'staketree-contracts/build/contracts/StakeTreeWithTokenizationFactory.json'; 4 | 5 | // Styling 6 | import './Deploy.css'; 7 | 8 | //Components 9 | import { Link } from 'react-router-dom'; 10 | 11 | let contractInstance; 12 | let contractInstanceWeb3; 13 | let web3Polling; 14 | 15 | class Deploy extends Component { 16 | constructor(props){ 17 | super(props); 18 | 19 | this.state = { 20 | contractAddress: "0x06afedaf28ca94be647418cbf9c02502f4554aa1", 21 | deployedAddresses: [], 22 | contractConfig: { 23 | beneficiaryAddress: "", 24 | withdrawalPeriod: 604800, // 1 week 25 | sunsetWithdrawalPeriod: 5184000, // 2 months 26 | minimumFundingAmount: 10000000000000000 // 0.01 ether 27 | } 28 | }; 29 | } 30 | async componentWillMount() { 31 | web3Polling = setInterval(async ()=> { 32 | if(typeof window.web3 !== 'undefined') { 33 | // dirty hack for web3@1.0.0 support for localhost testrpc, 34 | // see https://github.com/trufflesuite/truffle-contract/issues/56#issuecomment-331084530 35 | if (typeof window.web3.currentProvider.sendAsync !== "function") { 36 | window.web3.currentProvider.sendAsync = function() { 37 | return window.web3.currentProvider.send.apply( 38 | window.web3.currentProvider, 39 | arguments 40 | ); 41 | }; 42 | } 43 | 44 | const contract = TruffleContract(StakeTreeWithTokenizationFactory); 45 | contract.setProvider(window.web3.currentProvider); 46 | 47 | contractInstance = await contract.at(this.state.contractAddress); 48 | window.contractInstance = contractInstance; // debugging 49 | 50 | // Use the web3 instance of the contract to allow for async tx 51 | contractInstanceWeb3 = await window.web3.eth.contract(StakeTreeWithTokenizationFactory.abi).at(this.state.contractAddress); 52 | window.contractInstanceWeb3 = contractInstanceWeb3; // debugging 53 | 54 | window.web3.eth.getAccounts(async (error, accounts) => { 55 | if(this.state.currentEthAccount !== accounts[0]){ 56 | // RESET UI 57 | this.setState({ 58 | ...this.state, 59 | currentEthAccount: accounts[0], 60 | deployedAddresses: [], 61 | }); 62 | } 63 | const account = accounts[0]; 64 | const newContractAddresses = await contractInstance.getContractAddress.call({from: account}); 65 | 66 | // If we are currently deploying, don't update UI 67 | if(this.state.deployedAddresses.length > newContractAddresses.length) return; 68 | 69 | this.setState({deployedAddresses: newContractAddresses}); 70 | }); 71 | } 72 | }, 1500) 73 | } 74 | componentWillUnmount() { 75 | clearInterval(web3Polling); 76 | } 77 | 78 | async deploy() { 79 | let web3 = window.web3; // Uses web3 from metamask 80 | // Extra validation 81 | if(web3.isAddress(this.state.contractConfig.beneficiaryAddress)){ 82 | 83 | web3.eth.getAccounts(async (error, accounts) => { 84 | if(accounts.length > 0){ 85 | 86 | const account = accounts[0]; 87 | 88 | const nowUnix = new Date().getTime()/1000; 89 | const nowParsed = parseInt(nowUnix.toFixed(0), 10); 90 | 91 | contractInstanceWeb3.newContract( 92 | this.state.contractConfig.beneficiaryAddress, 93 | this.state.contractConfig.withdrawalPeriod, 94 | nowParsed, 95 | this.state.contractConfig.sunsetWithdrawalPeriod, 96 | this.state.contractConfig.minimumFundingAmount, 97 | {from: account}, 98 | function(error, tx){ 99 | const clone = this.state.deployedAddresses.slice(); 100 | clone.push("Deploying..."); 101 | this.setState({...this.state, deployedAddresses: clone}); 102 | console.log(tx); 103 | }.bind(this)); 104 | } 105 | }); 106 | } 107 | } 108 | 109 | handleBeneficiaryAddress(e) { 110 | this.setState({ 111 | ...this.state, 112 | contractConfig: { 113 | ...this.state.contractConfig, 114 | beneficiaryAddress: e.target.value 115 | } 116 | }) 117 | } 118 | 119 | render() { 120 | return ( 121 |
122 |
123 |
124 |

Deploy Contract

125 |

To get started with StakeTree we'll help you deploy a new instance of a StakeTree contract to the 126 | Ethereum blockchain. You can do this right from this page.

127 |

We've set up the contract configuration with some defaults.

128 |
    129 |
  • The withdrawal period is every 7 days.
  • 130 |
  • The minimum funding amount period is 0.01 ether.
  • 131 |
  • The sunset withdrawal period is 2 months.
  • 132 |
133 |

All we need from you is your beneficiary address and we're good to go!

134 | 135 | 136 | {this.state.deployedAddresses.length > 0 ?
137 |

Deployed contracts

138 |
    139 | {this.state.deployedAddresses.map(address => { 140 | return
  1. {address}
  2. 141 | })} 142 |
143 |
144 | : ''} 145 |
146 |
147 |
148 | ); 149 | } 150 | } 151 | 152 | export default Deploy; -------------------------------------------------------------------------------- /src/EtherscanLink.css: -------------------------------------------------------------------------------- 1 | .etherscanlink a.etherscanlink-anchor{ 2 | text-decoration: underline; 3 | color: #0FA0CE; 4 | } -------------------------------------------------------------------------------- /src/EtherscanLink.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import './EtherscanLink.css'; 4 | const EtherscanLink = ({text, type, id}) => { 5 | return ( 6 | {text} 7 | ); 8 | }; 9 | 10 | export default EtherscanLink; -------------------------------------------------------------------------------- /src/FAQ.css: -------------------------------------------------------------------------------- 1 | .faq h3 { 2 | margin-top: 10px; 3 | margin-bottom: 10px; 4 | } 5 | .faq h4 { 6 | font-size: 2rem; 7 | } 8 | 9 | .web3-info { 10 | border: 1px solid red; 11 | padding: 8px; 12 | border-radius: 5px; 13 | font-size: 1.3rem; 14 | margin-bottom: 20px; 15 | } -------------------------------------------------------------------------------- /src/FAQ.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | 3 | // Styling 4 | import './FAQ.css'; 5 | 6 | class FAQ extends Component { 7 | render() { 8 | return ( 9 |
10 |
11 |
12 |

FAQ

13 |
To use StakeTree you need to have Metamask installed. Metamask makes it really easy to interface with the Ethereum blockchain, so it's highly recommended.
14 |

How can I set up my own contract?

15 |

This is in development right now! Stay tuned.

16 | 17 |

How do I fund a contract?

18 |

You can send ether directly to the contract address or use one of the buttons on the creator's page.

19 | 20 |

As a beneficiary, how can I withdraw from the contract?

21 |

Select your beneficiary account in Metamask and head over to your creator page, a button will appear in the sidebar allowing you to withdraw.

22 | 23 |

As a funder, how can I refund my stake?

24 |

Select your funding account in Metamask and head over to the creator's page, a button will appear in the sidebar allowing you to refund your stake.

25 | 26 |

How much can the beneficiary withdraw?

27 |

The beneficiary can only withdraw 10% from their pool each week.

28 | 29 |

What happens when I add tokenization to my contract?

30 |

After each withdrawal, a staketree contract keeps track of how much each funder has contributed to the beneficiary. 31 | When a staktree contract is tokenized, this contribution amount, which is already kept track of, can be claimed as tokens. 32 | This allows the funders & beneficiary to use those tokens in any creative way possible. Tokenizing a contract cannot be reversed.

33 | 34 |

What are the token details?

35 |

When you add tokenization to your contract, you'll be asked to provide some details for your token. These can also not be changed once they're added.

36 |

The token name can be anything you prefer, eg StakeTree Tokens. The symbol (up to five letters) is a shorthand for your token. For example Ethereum's symbol is ETH, 37 | and Bitcoin's symbol BTC. The token decimal amount is up to how many decimals you'd want for your tokens. 18 is the default. It's the same amount that ether uses as well.

38 | 39 |

I really like this project and have some ideas, how do I share this?

40 |

You can contact the founder, Niel, directly: nieldlr@gmail.com.

41 |
42 |
43 |
44 | ); 45 | } 46 | } 47 | 48 | export default FAQ; -------------------------------------------------------------------------------- /src/FundButton.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | 3 | import web3store from "./Web3Store.js"; 4 | 5 | class FundButton extends Component { 6 | constructor(props) { 7 | super(props); 8 | this.state = { 9 | showTooltip: false 10 | } 11 | } 12 | showTooltip() { 13 | if(this.props.amount < this.props.minAmount) { 14 | this.setState({showTooltip: true}); 15 | } 16 | } 17 | hideTooltip() { 18 | this.setState({showTooltip: false}); 19 | } 20 | fund() { 21 | if(this.props.amount < this.props.minAmount) { 22 | return false; 23 | } 24 | let web3 = window.web3; // Uses web3 from metamask 25 | web3.eth.getAccounts((error, accounts) => { 26 | if(accounts.length > 0){ 27 | const account = accounts[0]; 28 | 29 | web3.eth.sendTransaction( 30 | {"from": account, "to": this.props.toAddress, "value": web3.toWei(this.props.amount, "ether")}, 31 | (err, transactionHash) => { 32 | if(!err) { 33 | web3store.addTransaction({type: 'stake', hash: transactionHash, mined: false}); 34 | } 35 | console.log(transactionHash); 36 | } 37 | ); 38 | } 39 | }); 40 | } 41 | render() { 42 | let tooltipClassNames = "tooltip"; 43 | if(this.state.showTooltip) tooltipClassNames += ' visible'; 44 | 45 | let buttonHtml = 46 |
{`The minimum funding amount is ${this.props.minAmount} ether.`}
47 | 48 |
; 49 | 50 | return buttonHtml; 51 | } 52 | }; 53 | 54 | export default FundButton; -------------------------------------------------------------------------------- /src/FunderCard.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | 3 | import RefundButton from './RefundButton.js'; 4 | import FundButton from './FundButton.js'; 5 | import ClaimTokensButton from './ClaimTokensButton.js'; 6 | 7 | import './ContractCard.css'; 8 | 9 | import Web3Controller from './Web3Controller.js'; 10 | import web3store from './Web3Store.js'; 11 | 12 | class FunderCard extends Component { 13 | constructor(props) { 14 | super(props); 15 | this.state = { 16 | customAmount: 0.1, 17 | stakeMore: false, 18 | funder: { 19 | balance: 0, 20 | contribution: 0, 21 | contributionClaimed: 0 22 | }, 23 | tokens: { 24 | balance: 0, 25 | symbol: '', 26 | decimals: 18 27 | } 28 | } 29 | } 30 | 31 | componentWillMount() { 32 | this.getContractDetails(); 33 | web3store.subscribe('funder-card', (newState)=>{ 34 | setTimeout(()=>{this.getContractDetails()}, 5000); 35 | }); 36 | } 37 | componentWillUnmount() { 38 | web3store.unsubscribe('funder-card'); 39 | } 40 | 41 | getContractDetails() { 42 | Web3Controller.getContractDetails({ 43 | id: 'funder-card-details', 44 | instance: this.props.contract, 45 | variables: ['version', 'minorVersion'], 46 | functions: [ 47 | {name: 'getFunderBalance', arg: this.props.currentAccount}, 48 | {name: 'getFunderContribution', arg: this.props.currentAccount}, 49 | {name: 'getFunderContributionClaimed', arg: this.props.currentAccount} 50 | ] 51 | }, (key, value) => { 52 | switch(key) { 53 | case 'getFunderBalance': 54 | key = 'balance'; 55 | break; 56 | case 'getFunderContribution': 57 | key = 'contribution'; 58 | break; 59 | case 'getFunderContributionClaimed': 60 | key = 'contributionClaimed'; 61 | break; 62 | default: 63 | break; 64 | } 65 | const newFunderState = {...this.state.funder}; 66 | newFunderState[key] = value; 67 | this.setState({ 68 | ...this.state, 69 | funder: newFunderState 70 | }); 71 | }); 72 | 73 | if(this.props.tokenized && this.props.tokenContract !== "0x0000000000000000000000000000000000000000") { 74 | const instance = Web3Controller.newInstance({ 75 | which: "TokenContract", 76 | at: this.props.tokenContract 77 | }); 78 | 79 | Web3Controller.getContractDetails({ 80 | id: 'tokens', 81 | instance: instance, 82 | variables: [ 83 | 'decimals', 'symbol' 84 | ], 85 | functions: [ 86 | { name: 'balanceOf', arg: this.props.currentAccount } 87 | ] 88 | }, (key, value) => { 89 | const newTokens = {...this.state.tokens}; 90 | if(key ==='balanceOf') key = 'balance'; 91 | newTokens[key] = value; 92 | this.setState({ 93 | ...this.state, 94 | tokens: newTokens 95 | }); 96 | }); 97 | } 98 | } 99 | 100 | toggleStakingOptions() { 101 | this.setState({stakeMore: !this.state.stakeMore}); 102 | } 103 | handleCustomAmount(e) { 104 | let value = e.target.value; 105 | if(e.target.value === "") value = 0.1; 106 | this.setState({customAmount: value}); 107 | } 108 | render() { 109 | const funderBalance = window.web3.fromWei(this.state.funder.balance, 'ether'); 110 | const funderContribution = window.web3.fromWei(this.state.funder.contribution, 'ether'); 111 | const funderClaimAmount = window.web3.fromWei(this.state.funder.contribution-this.state.funder.contributionClaimed, 'ether'); 112 | const tokenClaimAmount = this.state.funder.minorVersion === 1 ? funderClaimAmount*1000 : funderClaimAmount; 113 | 114 | const customAmount = this.state.customAmount > 0 ? this.state.customAmount : 0.1; 115 | 116 | // const minAmount = window.web3.fromWei(this.props.minAmount, 'ether'); 117 | 118 | return ( 119 |
120 |
121 |

Hi there funder,

122 |
    123 |
  • Currently staked: {funderBalance} ether.
  • 124 |
  • Total contributed: {funderContribution} ether.
  • 125 | {this.props.tokenized ?
  • Current token balance: {this.state.tokens.balance/Math.pow(10, this.state.tokens.decimals)} {this.state.tokens.symbol} tokens.
  • : ''} 126 | {this.props.tokenized ?
  • You can claim {tokenClaimAmount} tokens.
  • : '' } 127 |
128 |
129 | 130 | {this.state.stakeMore ? 131 |
132 | 133 | Stake {customAmount} Ether 134 |
135 | : 136 | ''} 137 | Claim Tokens 141 | 142 | Refund 145 |
146 |
147 |
148 | ) 149 | } 150 | }; 151 | 152 | export default FunderCard; -------------------------------------------------------------------------------- /src/Home.css: -------------------------------------------------------------------------------- 1 | .container { 2 | border-radius: 5px; 3 | } 4 | .header { 5 | margin-top: 10px; 6 | } 7 | 8 | .logo { 9 | text-align: center; 10 | color: yellow; 11 | } 12 | 13 | .tree-logo { 14 | font-size: 4em; 15 | margin-bottom: -10px; 16 | margin-top: 10px; 17 | } 18 | 19 | .featurette { 20 | text-align: center; 21 | padding: 10px; 22 | } 23 | 24 | .featurette h4 { 25 | font-size: 2.2rem; 26 | font-weight: 500; 27 | } 28 | 29 | .featurette-mini-text { 30 | font-size: 1rem; 31 | position: relative; 32 | top: -15px; 33 | } 34 | 35 | .content { 36 | padding-top: 10px; 37 | } 38 | 39 | img.avatar{ 40 | float: left; 41 | border-radius: 5px; 42 | height: 145px; 43 | margin: 2px 20px 10px 0px; 44 | } 45 | .info { 46 | text-align: left; 47 | } 48 | 49 | .no-web3 { 50 | font-size: 1.3rem; 51 | border: 1px solid #ff9b9b; 52 | border-radius: 5px; 53 | margin-bottom: 20px; 54 | padding: 10px; 55 | text-align: left; 56 | } 57 | 58 | .custom-value-input { 59 | width: 150px; 60 | margin-right: 10px; 61 | top: -1px; 62 | } 63 | 64 | .cta-buttons { 65 | text-align: center; 66 | } 67 | .cta-buttons button { 68 | display: inline-block; 69 | margin: 0px 5px 10px 0px; 70 | } 71 | 72 | .mc-hidden-input { 73 | position: absolute; left: -5000px; 74 | } 75 | .mc-label-email { 76 | width: 150px; 77 | display: inline-block; 78 | } 79 | .mc-field-group .email{ 80 | position: relative; 81 | top: -1px; 82 | margin-right: 10px; 83 | } 84 | 85 | @media(max-width: 500px){ 86 | img.avatar { 87 | height: 75px; 88 | margin: 10px 15px 0px 0px; 89 | } 90 | } 91 | 92 | @media(max-width: 420px){ 93 | .cta-buttons button { 94 | width: 100%; 95 | } 96 | .custom-value-input { 97 | margin-right: 10px; 98 | } 99 | .btn.custom-value-button { 100 | text-align: center; 101 | width: 100%; 102 | } 103 | } 104 | 105 | 106 | @media(max-width: 360px){ 107 | .cta-buttons button { 108 | width: 100%; 109 | font-size: 0.8rem; 110 | } 111 | 112 | } -------------------------------------------------------------------------------- /src/Home.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import './Home.css'; 3 | import { Link } from 'react-router-dom'; 4 | 5 | import Modal from 'react-modal'; 6 | 7 | import web3store from "./Web3Store.js"; 8 | 9 | const contractAddress = "0x8c79ec3f260b067157b0a7db0bb465f90b87f8f1"; 10 | 11 | class Home extends Component { 12 | constructor(props) { 13 | super(props); 14 | 15 | this.state = { 16 | customAmount: 5, 17 | showValueModal: false, 18 | web3available: typeof web3 !== 'undefined' 19 | }; 20 | 21 | window.addEventListener('load', function() { 22 | if (typeof web3 !== 'undefined') { 23 | this.setState({"web3available": true}); 24 | } 25 | }.bind(this)) 26 | } 27 | fund(etherAmount) { 28 | if(etherAmount < 0.01) { 29 | return this.setState({showValueModal: true}); 30 | } 31 | let web3 = window.web3; 32 | web3.eth.getAccounts((error, accounts) => { 33 | if(accounts.length > 0){ 34 | this.setState({web3available: true}); 35 | const account = accounts[0]; 36 | 37 | web3.eth.sendTransaction( 38 | {"from": account, "to": contractAddress, "value": web3.toWei(etherAmount, "ether")}, 39 | (err, transactionHash) => { 40 | if(!err) { 41 | web3store.addTransaction({type: 'stake', hash: transactionHash, mined: false}); 42 | } 43 | } 44 | ); 45 | } 46 | else { 47 | this.setState({web3available: false}); 48 | } 49 | }); 50 | } 51 | 52 | handleCustomAmount(e) { 53 | let value = e.target.value; 54 | this.setState({customAmount: value}); 55 | } 56 | 57 | noWeb3() { 58 | if(!this.state.web3available) { 59 | return

To fund StakeTree using the buttons below you need have MetaMask installed. If you have MetaMask installed, try unlocking it before trying again. Otherwise send ether to this address, {contractAddress}, using your preffered wallet.

; 60 | } 61 | return ""; 62 | } 63 | 64 | closeModal() { 65 | this.setState({showValueModal: false}); 66 | } 67 | 68 | render() { 69 | const noWeb3 = this.noWeb3(); 70 | 71 | const customAmount = this.state.customAmount > 0 ? this.state.customAmount : 10; 72 | 73 | return ( 74 |
75 | 82 |

So sorry!

83 |

The minimum funding amount is set to 0.01 ether at present. Try a bigger amount.

84 |
85 |
86 |
87 |

🙌

88 |
89 |
90 |

🌲

91 |
92 |
93 |

94 |
95 |
96 |
97 |
98 |
99 |

Stake Ether to your favorite creators

100 |

Help creators, teams & projects grow by funding their staketree smart contract.

101 |
102 |
103 |
104 |
105 |

Creators can withdraw funding

106 |

Every week creators can withdraw 10% from their fund, providing a steady cashflow.

107 |
108 |
109 |
110 |
111 |

Get your stake back at any time

112 |

Funders can withdraw what's left of their funding at any time.

113 |
114 |
115 |
116 |
117 | 118 |
119 |

More on StakeTree

120 | Niel's face 121 |

122 | Hi everyone. Niel de la Rouviere here. Welcome to StakeTree! I'm excited to introduce this project. I believe that to grow the crypto ecosystem 123 | (and hopefully much more in the future!) we need sustainable ways to fund projects & creators. ICOs are all the rage, but sometimes it just doesn't make 124 | sense for all that capital to be tied up, especially if your dapp doesn't need a token yet. 125 |

126 |

Using smart contracts on Ethereum, creators & funders can back projects with no intermediaries, fees and instant settlement.

127 |

There's lots more planned for StakeTree:

128 |
    129 |
  • Creating a simple UI for funders & creators to fund & withdraw from contracts.
  • 130 |
  • Develop funding tiers. This is where creators can reward dedicated backers with special rewards/access. Think tiers like Kickstarter & Patreon.
  • 131 |
  • Fund contracts with any ERC-20 token.
  • 132 |
  • Tokenization for funders & creators. When the creator withdraws ether, it mints tokens for all parties. These tokens can then be used for many things: voting, curation, special access, discounts and more. The creativity of the creator is the limit here.
  • 133 |
  • Create funding buckets. For example fund many Ethereum dev related projects using a single payment.
  • 134 |
  • Build a platform. Make it easy for creators to communicate with and build their communities.
  • 135 |
136 |

Plus many more ideas to come. But...

137 |

I need your help to build StakeTree.

138 |

In true dogfooding fashion, I'll be funding StakeTree using StakeTree itself. You can help fund development using the buttons below. If at any time you want to take back what's left of your ether, you can do this at any time.

139 | {noWeb3} 140 |
141 |
142 |
143 | 144 | 145 | 146 |
147 |

Stay up-to-date

148 |

Sign up to the mailing list (or follow development on Github & Twitter)

149 |
150 |
151 |
152 |
153 | 154 | 155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 | 164 |
165 |
166 |
167 | ); 168 | } 169 | } 170 | 171 | export default Home; -------------------------------------------------------------------------------- /src/Nav.css: -------------------------------------------------------------------------------- 1 | .nav-header a { 2 | text-decoration: none; 3 | color: #444; 4 | } 5 | .nav-header { 6 | border-bottom: 1px dashed #444; 7 | height: 45px; 8 | } 9 | .nav-logo { 10 | font-size: 2.5rem; 11 | } 12 | 13 | .nav-logo-text { 14 | color: #444; 15 | font-size: 2rem; 16 | margin-left: 10px; 17 | position: relative; 18 | bottom: 2px; 19 | } 20 | .right-nav-links { 21 | position: relative; 22 | top: 10px; 23 | float: right; 24 | } 25 | 26 | .right-nav-links a{ 27 | margin-left: 10px; 28 | } -------------------------------------------------------------------------------- /src/Nav.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Link } from 'react-router-dom'; 3 | 4 | import './Nav.css'; 5 | import Web3Hub from './Web3Hub.js'; 6 | 7 | const Nav = () => { 8 | return ( 9 |
10 |
11 | 🌲StakeTree 12 | 13 |
14 | FAQ | 15 | Dev Fund 16 |
17 | 18 | 19 |
20 |
21 | ); 22 | }; 23 | 24 | export default Nav; -------------------------------------------------------------------------------- /src/PageEditor.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { EditorState, convertToRaw, convertFromRaw } from 'draft-js'; 3 | import Editor from 'draft-js-plugins-editor'; 4 | import createToolbarPlugin from 'draft-js-static-toolbar-plugin'; 5 | import createLinkPlugin from 'draft-js-anchor-plugin'; 6 | 7 | import { 8 | ItalicButton, 9 | BoldButton, 10 | UnderlineButton, 11 | CodeButton, 12 | HeadlineOneButton, 13 | HeadlineTwoButton, 14 | HeadlineThreeButton, 15 | UnorderedListButton, 16 | OrderedListButton 17 | } from 'draft-js-buttons'; 18 | 19 | import './toolbarPlugin.css'; 20 | import './editorStyles.css'; 21 | 22 | class HeadlinesPicker extends Component { 23 | componentDidMount() { 24 | setTimeout(() => { window.addEventListener('click', this.onWindowClick); }); 25 | } 26 | 27 | componentWillUnmount() { 28 | window.removeEventListener('click', this.onWindowClick); 29 | } 30 | 31 | onWindowClick = () => 32 | // Call `onOverrideContent` again with `undefined` 33 | // so the toolbar can show its regular content again. 34 | this.props.onOverrideContent(undefined); 35 | 36 | render() { 37 | const buttons = [HeadlineOneButton, HeadlineTwoButton, HeadlineThreeButton]; 38 | return ( 39 |
40 | {buttons.map((Button, i) => // eslint-disable-next-line 41 |
44 | ); 45 | } 46 | } 47 | 48 | class HeadlinesButton extends Component { 49 | onClick = () => 50 | // A button can call `onOverrideContent` to replace the content 51 | // of the toolbar. This can be useful for displaying sub 52 | // menus or requesting additional information from the user. 53 | this.props.onOverrideContent(HeadlinesPicker); 54 | 55 | render() { 56 | return ( 57 |
58 | 61 |
62 | ); 63 | } 64 | } 65 | const linkPlugin = createLinkPlugin(); 66 | 67 | const toolbarPlugin = createToolbarPlugin({ 68 | structure: [ 69 | BoldButton, 70 | ItalicButton, 71 | UnderlineButton, 72 | CodeButton, 73 | HeadlinesButton, 74 | UnorderedListButton, 75 | OrderedListButton, 76 | linkPlugin.LinkButton 77 | ] 78 | }); 79 | 80 | const { Toolbar } = toolbarPlugin; 81 | const plugins = [toolbarPlugin, linkPlugin]; 82 | 83 | class PageEditor extends Component { 84 | constructor(props) { 85 | super(props); 86 | this.state = { 87 | editorState: EditorState.createWithContent(convertFromRaw(this.props.content)) 88 | }; 89 | } 90 | 91 | onChange = (editorState) => { 92 | this.setState({ 93 | editorState, 94 | }); 95 | }; 96 | 97 | focus = () => { 98 | this.editor.focus(); 99 | }; 100 | 101 | convert() { 102 | const data = convertToRaw(this.state.editorState.getCurrentContent()); 103 | 104 | let dataStr = "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(data)); 105 | let downloadAnchorNode = document.createElement('a'); 106 | downloadAnchorNode.setAttribute("href", dataStr); 107 | downloadAnchorNode.setAttribute("download", "pageData.json"); 108 | downloadAnchorNode.click(); 109 | downloadAnchorNode.remove(); 110 | } 111 | 112 | render() { 113 | return ( 114 |
115 |
116 | { this.editor = element; }} 122 | /> 123 | 124 | {!this.props.readOnly ? : ''} 125 |
126 | {!this.props.readOnly ? : ''} 127 |
128 | ); 129 | } 130 | } 131 | 132 | export default PageEditor; -------------------------------------------------------------------------------- /src/RefundButton.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import Modal from 'react-modal'; 3 | 4 | import web3store from "./Web3Store.js"; 5 | 6 | class RefundButton extends Component { 7 | constructor(props) { 8 | super(props); 9 | this.state = { 10 | showModal: false 11 | }; 12 | } 13 | showModal() { 14 | this.setState({showModal: true}); 15 | } 16 | closeModal() { 17 | this.setState({showModal: false}); 18 | } 19 | refund(e) { 20 | this.closeModal(); 21 | window.web3.eth.getAccounts(async (error, accounts) => { 22 | this.props.contract.refund({"from": accounts[0], "gas": 100000}, (err, txHash)=>{ 23 | if(!err) { 24 | web3store.addTransaction({type: 'refund', hash: txHash, mined: false}); 25 | } 26 | }); 27 | }); 28 | } 29 | render() { 30 | let buttonHtml = this.props.visible ? 31 | 40 |

Are you sure?

41 |

If you refund yourself we'll lose track of your past contributions & you might lose some benefits of being a funder.

42 | 43 | 44 |
45 | 46 |
: ; 47 | return buttonHtml; 48 | } 49 | 50 | }; 51 | 52 | export default RefundButton; -------------------------------------------------------------------------------- /src/SetMinAmountButton.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | 3 | import web3store from "./Web3Store.js"; 4 | 5 | class ClaimTokensButton extends Component { 6 | constructor(props) { 7 | super(props); 8 | this.state = { 9 | showTooltip: false 10 | } 11 | } 12 | showTooltip() { 13 | if(this.props.claimAmount <= 0) { 14 | this.setState({showTooltip: true}); 15 | } 16 | } 17 | hideTooltip() { 18 | this.setState({showTooltip: false}); 19 | } 20 | setMinAmount() { 21 | window.web3.eth.getAccounts(async (error, accounts) => { 22 | this.props.contract.setMinimumFundingAmount(window.web3.toWei(this.props.newMinAmount, 'ether'), {"from": accounts[0], "gas": 30000}, (err, txHash)=>{ 23 | if(!err) { 24 | web3store.addTransaction({type: 'set_min_amount', hash: txHash, mined: false}); 25 | } 26 | }); 27 | }); 28 | } 29 | render() { 30 | let tooltipClassNames = "tooltip"; 31 | if(this.state.showTooltip) tooltipClassNames += ' visible'; 32 | 33 | let buttonHtml = this.props.visible ? 34 |
{`You don't have any tokens to claim.`}
35 | 36 |
: ; 37 | 38 | return buttonHtml; 39 | } 40 | }; 41 | 42 | export default ClaimTokensButton; -------------------------------------------------------------------------------- /src/Web3Controller.js: -------------------------------------------------------------------------------- 1 | import StakeTreeWithTokenization from 'staketree-contracts/build/contracts/StakeTreeWithTokenization.json'; 2 | import StakeTreeMVP from 'staketree-contracts/build/contracts/StakeTreeMVP.json'; 3 | import TokenContract from 'staketree-contracts/build/contracts/MiniMeToken.json'; 4 | 5 | class ContractController { 6 | constructor() { 7 | this.contractABIs = { 8 | StakeTreeWithTokenization: StakeTreeWithTokenization.abi, 9 | StakeTreeMVP: StakeTreeMVP.abi, 10 | TokenContract: TokenContract.abi 11 | }; 12 | 13 | this.contractInstances = {}; 14 | this.subscriptions = {}; 15 | this.accountChangeSubscription = ''; 16 | 17 | window.addEventListener('load', ()=>{ 18 | if(typeof window.web3 !== 'undefined') { 19 | 20 | // dirty hack for web3@1.0.0 support for localhost testrpc, 21 | // see https://github.com/trufflesuite/truffle-contract/issues/56#issuecomment-331084530 22 | if (typeof window.web3.currentProvider.sendAsync !== "function") { 23 | window.web3.currentProvider.sendAsync = function() { 24 | return window.web3.currentProvider.send.apply( 25 | window.web3.currentProvider, 26 | arguments 27 | ); 28 | }; 29 | } 30 | } 31 | }); 32 | } 33 | 34 | newInstance(params) { 35 | const contract = window.web3.eth.contract(this.contractABIs[params.which]); 36 | return contract.at(params.at); 37 | } 38 | 39 | subscribeToAccountChange(cb) { 40 | let currentAccount; 41 | const interval = setInterval(()=>{ 42 | window.web3.eth.getAccounts((error, accounts)=>{ 43 | if(!error) { 44 | if(accounts.length) { // Check for locked Metamask 45 | if(!currentAccount){ 46 | currentAccount = accounts[0]; 47 | cb(currentAccount); 48 | } 49 | 50 | if(currentAccount !== accounts[0]) { 51 | currentAccount = accounts[0]; 52 | cb(currentAccount); 53 | } 54 | } 55 | else { 56 | cb("0x0000000000000000000000000000000000000000") 57 | } 58 | } 59 | 60 | }) 61 | }, 1500); 62 | this.accountChangeSubscription = interval; 63 | } 64 | 65 | unsubscribeFromAccountChange() { 66 | clearInterval(this.accountChangeSubscription); 67 | } 68 | 69 | getContractDetails(params, cb) { 70 | let instance = params.instance; 71 | if(params['variables']) { 72 | for(var i=0; i { 76 | if(!err) { 77 | let callbacKey = variable; 78 | let callbackValue = result; 79 | if(typeof result.toNumber === 'function') callbackValue = result.toNumber(); 80 | 81 | return cb(callbacKey, callbackValue); 82 | } 83 | }); 84 | })(i) 85 | } 86 | } 87 | 88 | if(params['functions']) { 89 | for(var j=0; j { 94 | if(!err) { 95 | let callbacKey = functionName; 96 | let callbackValue = result; 97 | if(typeof result.toNumber === 'function') callbackValue = result.toNumber(); 98 | return cb(callbacKey, callbackValue); 99 | } 100 | }); 101 | })(j) 102 | } 103 | } 104 | } 105 | 106 | subscribeToContract(params, cb) { 107 | const interval = setInterval(async ()=> { 108 | let instance = params.instance; 109 | if(params['variables']) { 110 | for(var i=0; i { 114 | if(!err) { 115 | let callbacKey = variable; 116 | let callbackValue = result; 117 | if(typeof result.toNumber === 'function') callbackValue = result.toNumber(); 118 | 119 | return cb(callbacKey, callbackValue); 120 | } 121 | }); 122 | })(i) 123 | } 124 | } 125 | 126 | if(params['functions']) { 127 | for(var j=0; j { 132 | if(!err) { 133 | let callbacKey = functionName; 134 | let callbackValue = result; 135 | if(typeof result.toNumber === 'function') callbackValue = result.toNumber(); 136 | return cb(callbacKey, callbackValue); 137 | } 138 | }); 139 | })(j) 140 | } 141 | } 142 | 143 | }, 2000); 144 | 145 | this.subscriptions[params.id] = interval; 146 | } 147 | 148 | getCurrentAccount(cb) { 149 | window.web3.eth.getAccounts((error, accounts)=>{ 150 | if(!error) { 151 | if(accounts.length > 0) { 152 | cb(accounts[0]); 153 | } // Check if Metamask isn't locked 154 | else { 155 | cb("0x0000000000000000000000000000000000000000"); 156 | } 157 | } 158 | 159 | }); 160 | } 161 | 162 | getWeb3() { 163 | return window.web3; 164 | } 165 | } 166 | 167 | 168 | export default new ContractController(); -------------------------------------------------------------------------------- /src/Web3Hub.css: -------------------------------------------------------------------------------- 1 | .web3-hub { 2 | padding: 0px 8px; 3 | float: right; 4 | border: 1px solid #ccc; 5 | border-radius: 4px; 6 | margin-left: 8px; 7 | cursor: pointer; 8 | background-color: #fff; 9 | right: 0px; 10 | top: 10px; 11 | z-index: 1; 12 | position: relative; 13 | } 14 | 15 | .web3-hub.opened { 16 | border-bottom: none; 17 | border-radius: 4px 4px 0px 0px; 18 | } 19 | 20 | .web3-hub.connected { 21 | color: green; 22 | border-color: green; 23 | } 24 | 25 | .web3-hub.not-connected { 26 | color: red; 27 | border-color: red; 28 | } 29 | 30 | /*.web3-hub.connected.not-main { 31 | border-color: yellow; 32 | }*/ 33 | 34 | .web3-hub .connect-string { 35 | display: inline-block; 36 | margin-right: 4px; 37 | } 38 | 39 | .web3-drawer { 40 | position: absolute; 41 | padding: 8px 8px; 42 | margin-top: 10px; 43 | width: 101%; 44 | border: 1px solid green; 45 | border-top: none; 46 | top: 12px; 47 | left: -1px; 48 | padding-top: 16px; 49 | border-radius: 0px 0px 4px 4px; 50 | background-color: #fff; 51 | box-sizing: border-box; 52 | } 53 | 54 | .web3-drawer li{ 55 | overflow: hidden; 56 | list-style: none; 57 | border-top: 1px solid #ddd; 58 | 59 | padding: 4px; 60 | white-space: nowrap; 61 | text-overflow: ellipsis; 62 | font-size: 1.3rem; 63 | 64 | margin: 0px; 65 | top: -4px; 66 | position: relative; 67 | } 68 | 69 | .web3-drawer li:last-child { 70 | border-bottom: 1px solid #ddd; 71 | } 72 | 73 | .web3-drawer li i { 74 | padding: 0px 4px; 75 | } 76 | 77 | .web3-hub.not-connected .web3-drawer { 78 | color: red; 79 | border-color: red; 80 | } -------------------------------------------------------------------------------- /src/Web3Hub.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import _ from 'lodash'; 3 | 4 | import './Web3Hub.css'; 5 | import web3store from "./Web3Store.js"; 6 | 7 | import EtherscanLink from './EtherscanLink.js'; 8 | 9 | class Web3Hub extends Component { 10 | constructor(props) { 11 | super(props); 12 | this.state = { 13 | network: "Unknown", 14 | connected: false, 15 | transacting: false, 16 | showDrawer: false, 17 | transactions: web3store.getState().transactions 18 | }; 19 | 20 | let pollingCounter = 0; 21 | // Poll for account/web3 changes 22 | setInterval(async ()=> { 23 | if(typeof window.web3 !== 'undefined') { 24 | 25 | // dirty hack for web3@1.0.0 support for localhost testrpc, 26 | // see https://github.com/trufflesuite/truffle-contract/issues/56#issuecomment-331084530 27 | if (typeof window.web3.currentProvider.sendAsync !== "function") { 28 | window.web3.currentProvider.sendAsync = function() { 29 | return window.web3.currentProvider.send.apply( 30 | window.web3.currentProvider, 31 | arguments 32 | ); 33 | }; 34 | } 35 | 36 | window.web3.version.getNetwork((err, result) => { 37 | let networkName; 38 | switch (result) { 39 | case "1": 40 | networkName = "Main Net"; 41 | break; 42 | case "2": 43 | networkName = "Morden"; 44 | break; 45 | case "3": 46 | networkName = "Ropsten"; 47 | break; 48 | case "4": 49 | networkName = "Rinkeby"; 50 | break; 51 | case "42": 52 | networkName = "Kovan"; 53 | break; 54 | default: 55 | networkName = "Unknown"; 56 | } 57 | 58 | this.setState({network: networkName}); 59 | }); 60 | 61 | this.setState({connected: true}); 62 | 63 | // Poll transactions 64 | const unminedTransactions = _.filter(this.state.transactions, function(tx) { return !tx.mined; }); 65 | if(unminedTransactions.length>0) { 66 | for(var i=0; i{ 69 | if(result && (result.blockNumber || result.status)) { 70 | web3store.setTransactionAsMined(tx.hash); 71 | } 72 | }); 73 | } 74 | } 75 | else { 76 | this.setState({transacting: false}); 77 | } 78 | } 79 | else { 80 | pollingCounter++; 81 | if(pollingCounter === 3) { 82 | this.setState({connected: false}); 83 | } 84 | } 85 | }, 1500); 86 | 87 | web3store.subscribe('web3-hub', (newState)=>{ 88 | this.setState({transactions: newState.transactions}); 89 | this.setState({transacting: true}); 90 | }); 91 | } 92 | 93 | toggleDrawer() { 94 | this.setState({showDrawer: !this.state.showDrawer}); 95 | } 96 | 97 | getFriendlyTransactionText(type, mined) { 98 | let friendlyText = ''; 99 | if(mined) return "Confirmed"; 100 | switch (type) { 101 | case "stake": 102 | friendlyText = "Staking..."; 103 | break; 104 | case "refund": 105 | friendlyText = "Refunding..."; 106 | break; 107 | default: 108 | friendlyText = "Pending..."; 109 | } 110 | 111 | return friendlyText; 112 | } 113 | 114 | render() { 115 | const connectString = this.state.connected ? `Connected to ${this.state.network}` : `Not connected`; 116 | let web3classnames = "web3-hub"; 117 | if(this.state.connected) web3classnames += ' connected'; 118 | if(!this.state.connected) web3classnames += ' not-connected'; 119 | 120 | if(this.state.connected && this.state.network !== 'Main Net') web3classnames += ' not-main'; 121 | 122 | if(this.state.showDrawer) web3classnames += ' opened'; 123 | 124 | const txKeys = Object.keys(this.state.transactions).reverse(); 125 | return ( 126 |
127 | 128 | {connectString} 129 | {this.state.connected ? {this.state.transacting ? : } : } 130 | 131 | {this.state.showDrawer ? 132 |
133 | {this.state.connected ? 134 | 135 | {txKeys.length ? 136 |
    137 | {txKeys.map((key)=>{ 138 | const tx = this.state.transactions[key]; 139 | return
  • 140 | {tx.mined ? : } 141 |
  • 142 | })} 143 |
144 | : "No new transactions." 145 | } 146 |
147 | : Install MetaMask to improve your StakeTree experience. } 148 | 149 |
150 | :'' } 151 | 152 |
153 | ) 154 | 155 | } 156 | } 157 | 158 | export default Web3Hub; -------------------------------------------------------------------------------- /src/Web3Store.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | 3 | class Web3Store { 4 | constructor() { 5 | this.subFunctions = []; 6 | this.funcIndex = {}; 7 | this.state = { 8 | transactions: {} 9 | } 10 | } 11 | 12 | getState() { 13 | return this.state; 14 | } 15 | 16 | subscribe(id, listenerFunc) { 17 | if(typeof this.funcIndex[id] === 'undefined'){ 18 | this.funcIndex[id] = listenerFunc; 19 | } 20 | } 21 | 22 | unsubscribe(id){ 23 | delete this.funcIndex[id]; 24 | } 25 | 26 | pushCallbacks() { 27 | const funcIds = Object.keys(this.funcIndex); 28 | for(var i=0; i { 26 | this.props.contract.withdraw({"from": accounts[0], "gas": 100000}, (err, txHash)=>{ 27 | if(!err) { 28 | web3store.addTransaction({type: 'withdraw', hash: txHash, mined: false}); 29 | } 30 | }); 31 | }); 32 | } 33 | render() { 34 | let tooltipClassNames = "tooltip"; 35 | if(this.state.showTooltip) tooltipClassNames += ' visible'; 36 | 37 | let buttonHtml = this.props.visible ? 38 |
{`You can only withdraw after ${this.props.withdrawalDate.toLocaleString()}.`}
39 | 40 |
: ; 41 | 42 | return buttonHtml; 43 | } 44 | }; 45 | 46 | export default WithdrawButton; -------------------------------------------------------------------------------- /src/creatorsToIPFSMap.json: -------------------------------------------------------------------------------- 1 | { 2 | "/dev": "QmPcb9szrMQHErragFcU58sEh1xMsP21HEkdFPRkzDhacc", 3 | "/rhyslindmark": "QmZaxSvEXfbN6353vJJrtRBQWsJ6ak5uCzojLaGSpx8SUp", 4 | "/effectivealtruism": "QmSieKJQJv54qLos5WEV1xVW3WZDHLL5BEqQtb1DQ1PJwn", 5 | "/tokeneconomy": "QmVmy1H7m2hko4Vq2gxFMxndB6fxvVHcCPVVNCsM1sLoQt" 6 | } -------------------------------------------------------------------------------- /src/editorStyles.css: -------------------------------------------------------------------------------- 1 | .editor { 2 | box-sizing: border-box; 3 | border: 1px solid #ddd; 4 | cursor: text; 5 | padding: 16px; 6 | border-radius: 2px; 7 | margin-bottom: 2em; 8 | box-shadow: inset 0px 1px 8px -3px #ABABAB; 9 | background: #fefefe; 10 | } 11 | 12 | .editor :global(.public-DraftEditor-content) { 13 | min-height: 140px; 14 | } -------------------------------------------------------------------------------- /src/font-awesome/HELP-US-OUT.txt: -------------------------------------------------------------------------------- 1 | I hope you love Font Awesome. If you've found it useful, please do me a favor and check out my latest project, 2 | Fort Awesome (https://fortawesome.com). It makes it easy to put the perfect icons on your website. Choose from our awesome, 3 | comprehensive icon sets or copy and paste your own. 4 | 5 | Please. Check it out. 6 | 7 | -Dave Gandy 8 | -------------------------------------------------------------------------------- /src/font-awesome/fonts/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StakeTree/site/5a4ece37fa0811853d8a877bcc59bc2d65d4ce6e/src/font-awesome/fonts/FontAwesome.otf -------------------------------------------------------------------------------- /src/font-awesome/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StakeTree/site/5a4ece37fa0811853d8a877bcc59bc2d65d4ce6e/src/font-awesome/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /src/font-awesome/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StakeTree/site/5a4ece37fa0811853d8a877bcc59bc2d65d4ce6e/src/font-awesome/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /src/font-awesome/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StakeTree/site/5a4ece37fa0811853d8a877bcc59bc2d65d4ce6e/src/font-awesome/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /src/font-awesome/fonts/fontawesome-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StakeTree/site/5a4ece37fa0811853d8a877bcc59bc2d65d4ce6e/src/font-awesome/fonts/fontawesome-webfont.woff2 -------------------------------------------------------------------------------- /src/font-awesome/less/animated.less: -------------------------------------------------------------------------------- 1 | // Animated Icons 2 | // -------------------------- 3 | 4 | .@{fa-css-prefix}-spin { 5 | -webkit-animation: fa-spin 2s infinite linear; 6 | animation: fa-spin 2s infinite linear; 7 | } 8 | 9 | .@{fa-css-prefix}-pulse { 10 | -webkit-animation: fa-spin 1s infinite steps(8); 11 | animation: fa-spin 1s infinite steps(8); 12 | } 13 | 14 | @-webkit-keyframes fa-spin { 15 | 0% { 16 | -webkit-transform: rotate(0deg); 17 | transform: rotate(0deg); 18 | } 19 | 100% { 20 | -webkit-transform: rotate(359deg); 21 | transform: rotate(359deg); 22 | } 23 | } 24 | 25 | @keyframes fa-spin { 26 | 0% { 27 | -webkit-transform: rotate(0deg); 28 | transform: rotate(0deg); 29 | } 30 | 100% { 31 | -webkit-transform: rotate(359deg); 32 | transform: rotate(359deg); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/font-awesome/less/bordered-pulled.less: -------------------------------------------------------------------------------- 1 | // Bordered & Pulled 2 | // ------------------------- 3 | 4 | .@{fa-css-prefix}-border { 5 | padding: .2em .25em .15em; 6 | border: solid .08em @fa-border-color; 7 | border-radius: .1em; 8 | } 9 | 10 | .@{fa-css-prefix}-pull-left { float: left; } 11 | .@{fa-css-prefix}-pull-right { float: right; } 12 | 13 | .@{fa-css-prefix} { 14 | &.@{fa-css-prefix}-pull-left { margin-right: .3em; } 15 | &.@{fa-css-prefix}-pull-right { margin-left: .3em; } 16 | } 17 | 18 | /* Deprecated as of 4.4.0 */ 19 | .pull-right { float: right; } 20 | .pull-left { float: left; } 21 | 22 | .@{fa-css-prefix} { 23 | &.pull-left { margin-right: .3em; } 24 | &.pull-right { margin-left: .3em; } 25 | } 26 | -------------------------------------------------------------------------------- /src/font-awesome/less/core.less: -------------------------------------------------------------------------------- 1 | // Base Class Definition 2 | // ------------------------- 3 | 4 | .@{fa-css-prefix} { 5 | display: inline-block; 6 | font: normal normal normal @fa-font-size-base/@fa-line-height-base FontAwesome; // shortening font declaration 7 | font-size: inherit; // can't have font-size inherit on line above, so need to override 8 | text-rendering: auto; // optimizelegibility throws things off #1094 9 | -webkit-font-smoothing: antialiased; 10 | -moz-osx-font-smoothing: grayscale; 11 | 12 | } 13 | -------------------------------------------------------------------------------- /src/font-awesome/less/fixed-width.less: -------------------------------------------------------------------------------- 1 | // Fixed Width Icons 2 | // ------------------------- 3 | .@{fa-css-prefix}-fw { 4 | width: (18em / 14); 5 | text-align: center; 6 | } 7 | -------------------------------------------------------------------------------- /src/font-awesome/less/font-awesome.less: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome 3 | * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) 4 | */ 5 | 6 | @import "variables.less"; 7 | @import "mixins.less"; 8 | @import "path.less"; 9 | @import "core.less"; 10 | @import "larger.less"; 11 | @import "fixed-width.less"; 12 | @import "list.less"; 13 | @import "bordered-pulled.less"; 14 | @import "animated.less"; 15 | @import "rotated-flipped.less"; 16 | @import "stacked.less"; 17 | @import "icons.less"; 18 | @import "screen-reader.less"; 19 | -------------------------------------------------------------------------------- /src/font-awesome/less/larger.less: -------------------------------------------------------------------------------- 1 | // Icon Sizes 2 | // ------------------------- 3 | 4 | /* makes the font 33% larger relative to the icon container */ 5 | .@{fa-css-prefix}-lg { 6 | font-size: (4em / 3); 7 | line-height: (3em / 4); 8 | vertical-align: -15%; 9 | } 10 | .@{fa-css-prefix}-2x { font-size: 2em; } 11 | .@{fa-css-prefix}-3x { font-size: 3em; } 12 | .@{fa-css-prefix}-4x { font-size: 4em; } 13 | .@{fa-css-prefix}-5x { font-size: 5em; } 14 | -------------------------------------------------------------------------------- /src/font-awesome/less/list.less: -------------------------------------------------------------------------------- 1 | // List Icons 2 | // ------------------------- 3 | 4 | .@{fa-css-prefix}-ul { 5 | padding-left: 0; 6 | margin-left: @fa-li-width; 7 | list-style-type: none; 8 | > li { position: relative; } 9 | } 10 | .@{fa-css-prefix}-li { 11 | position: absolute; 12 | left: -@fa-li-width; 13 | width: @fa-li-width; 14 | top: (2em / 14); 15 | text-align: center; 16 | &.@{fa-css-prefix}-lg { 17 | left: (-@fa-li-width + (4em / 14)); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/font-awesome/less/mixins.less: -------------------------------------------------------------------------------- 1 | // Mixins 2 | // -------------------------- 3 | 4 | .fa-icon() { 5 | display: inline-block; 6 | font: normal normal normal @fa-font-size-base/@fa-line-height-base FontAwesome; // shortening font declaration 7 | font-size: inherit; // can't have font-size inherit on line above, so need to override 8 | text-rendering: auto; // optimizelegibility throws things off #1094 9 | -webkit-font-smoothing: antialiased; 10 | -moz-osx-font-smoothing: grayscale; 11 | 12 | } 13 | 14 | .fa-icon-rotate(@degrees, @rotation) { 15 | -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=@{rotation})"; 16 | -webkit-transform: rotate(@degrees); 17 | -ms-transform: rotate(@degrees); 18 | transform: rotate(@degrees); 19 | } 20 | 21 | .fa-icon-flip(@horiz, @vert, @rotation) { 22 | -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=@{rotation}, mirror=1)"; 23 | -webkit-transform: scale(@horiz, @vert); 24 | -ms-transform: scale(@horiz, @vert); 25 | transform: scale(@horiz, @vert); 26 | } 27 | 28 | 29 | // Only display content to screen readers. A la Bootstrap 4. 30 | // 31 | // See: http://a11yproject.com/posts/how-to-hide-content/ 32 | 33 | .sr-only() { 34 | position: absolute; 35 | width: 1px; 36 | height: 1px; 37 | padding: 0; 38 | margin: -1px; 39 | overflow: hidden; 40 | clip: rect(0,0,0,0); 41 | border: 0; 42 | } 43 | 44 | // Use in conjunction with .sr-only to only display content when it's focused. 45 | // 46 | // Useful for "Skip to main content" links; see http://www.w3.org/TR/2013/NOTE-WCAG20-TECHS-20130905/G1 47 | // 48 | // Credit: HTML5 Boilerplate 49 | 50 | .sr-only-focusable() { 51 | &:active, 52 | &:focus { 53 | position: static; 54 | width: auto; 55 | height: auto; 56 | margin: 0; 57 | overflow: visible; 58 | clip: auto; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/font-awesome/less/path.less: -------------------------------------------------------------------------------- 1 | /* FONT PATH 2 | * -------------------------- */ 3 | 4 | @font-face { 5 | font-family: 'FontAwesome'; 6 | src: url('@{fa-font-path}/fontawesome-webfont.eot?v=@{fa-version}'); 7 | src: url('@{fa-font-path}/fontawesome-webfont.eot?#iefix&v=@{fa-version}') format('embedded-opentype'), 8 | url('@{fa-font-path}/fontawesome-webfont.woff2?v=@{fa-version}') format('woff2'), 9 | url('@{fa-font-path}/fontawesome-webfont.woff?v=@{fa-version}') format('woff'), 10 | url('@{fa-font-path}/fontawesome-webfont.ttf?v=@{fa-version}') format('truetype'), 11 | url('@{fa-font-path}/fontawesome-webfont.svg?v=@{fa-version}#fontawesomeregular') format('svg'); 12 | // src: url('@{fa-font-path}/FontAwesome.otf') format('opentype'); // used when developing fonts 13 | font-weight: normal; 14 | font-style: normal; 15 | } 16 | -------------------------------------------------------------------------------- /src/font-awesome/less/rotated-flipped.less: -------------------------------------------------------------------------------- 1 | // Rotated & Flipped Icons 2 | // ------------------------- 3 | 4 | .@{fa-css-prefix}-rotate-90 { .fa-icon-rotate(90deg, 1); } 5 | .@{fa-css-prefix}-rotate-180 { .fa-icon-rotate(180deg, 2); } 6 | .@{fa-css-prefix}-rotate-270 { .fa-icon-rotate(270deg, 3); } 7 | 8 | .@{fa-css-prefix}-flip-horizontal { .fa-icon-flip(-1, 1, 0); } 9 | .@{fa-css-prefix}-flip-vertical { .fa-icon-flip(1, -1, 2); } 10 | 11 | // Hook for IE8-9 12 | // ------------------------- 13 | 14 | :root .@{fa-css-prefix}-rotate-90, 15 | :root .@{fa-css-prefix}-rotate-180, 16 | :root .@{fa-css-prefix}-rotate-270, 17 | :root .@{fa-css-prefix}-flip-horizontal, 18 | :root .@{fa-css-prefix}-flip-vertical { 19 | filter: none; 20 | } 21 | -------------------------------------------------------------------------------- /src/font-awesome/less/screen-reader.less: -------------------------------------------------------------------------------- 1 | // Screen Readers 2 | // ------------------------- 3 | 4 | .sr-only { .sr-only(); } 5 | .sr-only-focusable { .sr-only-focusable(); } 6 | -------------------------------------------------------------------------------- /src/font-awesome/less/stacked.less: -------------------------------------------------------------------------------- 1 | // Stacked Icons 2 | // ------------------------- 3 | 4 | .@{fa-css-prefix}-stack { 5 | position: relative; 6 | display: inline-block; 7 | width: 2em; 8 | height: 2em; 9 | line-height: 2em; 10 | vertical-align: middle; 11 | } 12 | .@{fa-css-prefix}-stack-1x, .@{fa-css-prefix}-stack-2x { 13 | position: absolute; 14 | left: 0; 15 | width: 100%; 16 | text-align: center; 17 | } 18 | .@{fa-css-prefix}-stack-1x { line-height: inherit; } 19 | .@{fa-css-prefix}-stack-2x { font-size: 2em; } 20 | .@{fa-css-prefix}-inverse { color: @fa-inverse; } 21 | -------------------------------------------------------------------------------- /src/font-awesome/less/variables.less: -------------------------------------------------------------------------------- 1 | // Variables 2 | // -------------------------- 3 | 4 | @fa-font-path: "../fonts"; 5 | @fa-font-size-base: 14px; 6 | @fa-line-height-base: 1; 7 | //@fa-font-path: "//netdna.bootstrapcdn.com/font-awesome/4.7.0/fonts"; // for referencing Bootstrap CDN font files directly 8 | @fa-css-prefix: fa; 9 | @fa-version: "4.7.0"; 10 | @fa-border-color: #eee; 11 | @fa-inverse: #fff; 12 | @fa-li-width: (30em / 14); 13 | 14 | @fa-var-500px: "\f26e"; 15 | @fa-var-address-book: "\f2b9"; 16 | @fa-var-address-book-o: "\f2ba"; 17 | @fa-var-address-card: "\f2bb"; 18 | @fa-var-address-card-o: "\f2bc"; 19 | @fa-var-adjust: "\f042"; 20 | @fa-var-adn: "\f170"; 21 | @fa-var-align-center: "\f037"; 22 | @fa-var-align-justify: "\f039"; 23 | @fa-var-align-left: "\f036"; 24 | @fa-var-align-right: "\f038"; 25 | @fa-var-amazon: "\f270"; 26 | @fa-var-ambulance: "\f0f9"; 27 | @fa-var-american-sign-language-interpreting: "\f2a3"; 28 | @fa-var-anchor: "\f13d"; 29 | @fa-var-android: "\f17b"; 30 | @fa-var-angellist: "\f209"; 31 | @fa-var-angle-double-down: "\f103"; 32 | @fa-var-angle-double-left: "\f100"; 33 | @fa-var-angle-double-right: "\f101"; 34 | @fa-var-angle-double-up: "\f102"; 35 | @fa-var-angle-down: "\f107"; 36 | @fa-var-angle-left: "\f104"; 37 | @fa-var-angle-right: "\f105"; 38 | @fa-var-angle-up: "\f106"; 39 | @fa-var-apple: "\f179"; 40 | @fa-var-archive: "\f187"; 41 | @fa-var-area-chart: "\f1fe"; 42 | @fa-var-arrow-circle-down: "\f0ab"; 43 | @fa-var-arrow-circle-left: "\f0a8"; 44 | @fa-var-arrow-circle-o-down: "\f01a"; 45 | @fa-var-arrow-circle-o-left: "\f190"; 46 | @fa-var-arrow-circle-o-right: "\f18e"; 47 | @fa-var-arrow-circle-o-up: "\f01b"; 48 | @fa-var-arrow-circle-right: "\f0a9"; 49 | @fa-var-arrow-circle-up: "\f0aa"; 50 | @fa-var-arrow-down: "\f063"; 51 | @fa-var-arrow-left: "\f060"; 52 | @fa-var-arrow-right: "\f061"; 53 | @fa-var-arrow-up: "\f062"; 54 | @fa-var-arrows: "\f047"; 55 | @fa-var-arrows-alt: "\f0b2"; 56 | @fa-var-arrows-h: "\f07e"; 57 | @fa-var-arrows-v: "\f07d"; 58 | @fa-var-asl-interpreting: "\f2a3"; 59 | @fa-var-assistive-listening-systems: "\f2a2"; 60 | @fa-var-asterisk: "\f069"; 61 | @fa-var-at: "\f1fa"; 62 | @fa-var-audio-description: "\f29e"; 63 | @fa-var-automobile: "\f1b9"; 64 | @fa-var-backward: "\f04a"; 65 | @fa-var-balance-scale: "\f24e"; 66 | @fa-var-ban: "\f05e"; 67 | @fa-var-bandcamp: "\f2d5"; 68 | @fa-var-bank: "\f19c"; 69 | @fa-var-bar-chart: "\f080"; 70 | @fa-var-bar-chart-o: "\f080"; 71 | @fa-var-barcode: "\f02a"; 72 | @fa-var-bars: "\f0c9"; 73 | @fa-var-bath: "\f2cd"; 74 | @fa-var-bathtub: "\f2cd"; 75 | @fa-var-battery: "\f240"; 76 | @fa-var-battery-0: "\f244"; 77 | @fa-var-battery-1: "\f243"; 78 | @fa-var-battery-2: "\f242"; 79 | @fa-var-battery-3: "\f241"; 80 | @fa-var-battery-4: "\f240"; 81 | @fa-var-battery-empty: "\f244"; 82 | @fa-var-battery-full: "\f240"; 83 | @fa-var-battery-half: "\f242"; 84 | @fa-var-battery-quarter: "\f243"; 85 | @fa-var-battery-three-quarters: "\f241"; 86 | @fa-var-bed: "\f236"; 87 | @fa-var-beer: "\f0fc"; 88 | @fa-var-behance: "\f1b4"; 89 | @fa-var-behance-square: "\f1b5"; 90 | @fa-var-bell: "\f0f3"; 91 | @fa-var-bell-o: "\f0a2"; 92 | @fa-var-bell-slash: "\f1f6"; 93 | @fa-var-bell-slash-o: "\f1f7"; 94 | @fa-var-bicycle: "\f206"; 95 | @fa-var-binoculars: "\f1e5"; 96 | @fa-var-birthday-cake: "\f1fd"; 97 | @fa-var-bitbucket: "\f171"; 98 | @fa-var-bitbucket-square: "\f172"; 99 | @fa-var-bitcoin: "\f15a"; 100 | @fa-var-black-tie: "\f27e"; 101 | @fa-var-blind: "\f29d"; 102 | @fa-var-bluetooth: "\f293"; 103 | @fa-var-bluetooth-b: "\f294"; 104 | @fa-var-bold: "\f032"; 105 | @fa-var-bolt: "\f0e7"; 106 | @fa-var-bomb: "\f1e2"; 107 | @fa-var-book: "\f02d"; 108 | @fa-var-bookmark: "\f02e"; 109 | @fa-var-bookmark-o: "\f097"; 110 | @fa-var-braille: "\f2a1"; 111 | @fa-var-briefcase: "\f0b1"; 112 | @fa-var-btc: "\f15a"; 113 | @fa-var-bug: "\f188"; 114 | @fa-var-building: "\f1ad"; 115 | @fa-var-building-o: "\f0f7"; 116 | @fa-var-bullhorn: "\f0a1"; 117 | @fa-var-bullseye: "\f140"; 118 | @fa-var-bus: "\f207"; 119 | @fa-var-buysellads: "\f20d"; 120 | @fa-var-cab: "\f1ba"; 121 | @fa-var-calculator: "\f1ec"; 122 | @fa-var-calendar: "\f073"; 123 | @fa-var-calendar-check-o: "\f274"; 124 | @fa-var-calendar-minus-o: "\f272"; 125 | @fa-var-calendar-o: "\f133"; 126 | @fa-var-calendar-plus-o: "\f271"; 127 | @fa-var-calendar-times-o: "\f273"; 128 | @fa-var-camera: "\f030"; 129 | @fa-var-camera-retro: "\f083"; 130 | @fa-var-car: "\f1b9"; 131 | @fa-var-caret-down: "\f0d7"; 132 | @fa-var-caret-left: "\f0d9"; 133 | @fa-var-caret-right: "\f0da"; 134 | @fa-var-caret-square-o-down: "\f150"; 135 | @fa-var-caret-square-o-left: "\f191"; 136 | @fa-var-caret-square-o-right: "\f152"; 137 | @fa-var-caret-square-o-up: "\f151"; 138 | @fa-var-caret-up: "\f0d8"; 139 | @fa-var-cart-arrow-down: "\f218"; 140 | @fa-var-cart-plus: "\f217"; 141 | @fa-var-cc: "\f20a"; 142 | @fa-var-cc-amex: "\f1f3"; 143 | @fa-var-cc-diners-club: "\f24c"; 144 | @fa-var-cc-discover: "\f1f2"; 145 | @fa-var-cc-jcb: "\f24b"; 146 | @fa-var-cc-mastercard: "\f1f1"; 147 | @fa-var-cc-paypal: "\f1f4"; 148 | @fa-var-cc-stripe: "\f1f5"; 149 | @fa-var-cc-visa: "\f1f0"; 150 | @fa-var-certificate: "\f0a3"; 151 | @fa-var-chain: "\f0c1"; 152 | @fa-var-chain-broken: "\f127"; 153 | @fa-var-check: "\f00c"; 154 | @fa-var-check-circle: "\f058"; 155 | @fa-var-check-circle-o: "\f05d"; 156 | @fa-var-check-square: "\f14a"; 157 | @fa-var-check-square-o: "\f046"; 158 | @fa-var-chevron-circle-down: "\f13a"; 159 | @fa-var-chevron-circle-left: "\f137"; 160 | @fa-var-chevron-circle-right: "\f138"; 161 | @fa-var-chevron-circle-up: "\f139"; 162 | @fa-var-chevron-down: "\f078"; 163 | @fa-var-chevron-left: "\f053"; 164 | @fa-var-chevron-right: "\f054"; 165 | @fa-var-chevron-up: "\f077"; 166 | @fa-var-child: "\f1ae"; 167 | @fa-var-chrome: "\f268"; 168 | @fa-var-circle: "\f111"; 169 | @fa-var-circle-o: "\f10c"; 170 | @fa-var-circle-o-notch: "\f1ce"; 171 | @fa-var-circle-thin: "\f1db"; 172 | @fa-var-clipboard: "\f0ea"; 173 | @fa-var-clock-o: "\f017"; 174 | @fa-var-clone: "\f24d"; 175 | @fa-var-close: "\f00d"; 176 | @fa-var-cloud: "\f0c2"; 177 | @fa-var-cloud-download: "\f0ed"; 178 | @fa-var-cloud-upload: "\f0ee"; 179 | @fa-var-cny: "\f157"; 180 | @fa-var-code: "\f121"; 181 | @fa-var-code-fork: "\f126"; 182 | @fa-var-codepen: "\f1cb"; 183 | @fa-var-codiepie: "\f284"; 184 | @fa-var-coffee: "\f0f4"; 185 | @fa-var-cog: "\f013"; 186 | @fa-var-cogs: "\f085"; 187 | @fa-var-columns: "\f0db"; 188 | @fa-var-comment: "\f075"; 189 | @fa-var-comment-o: "\f0e5"; 190 | @fa-var-commenting: "\f27a"; 191 | @fa-var-commenting-o: "\f27b"; 192 | @fa-var-comments: "\f086"; 193 | @fa-var-comments-o: "\f0e6"; 194 | @fa-var-compass: "\f14e"; 195 | @fa-var-compress: "\f066"; 196 | @fa-var-connectdevelop: "\f20e"; 197 | @fa-var-contao: "\f26d"; 198 | @fa-var-copy: "\f0c5"; 199 | @fa-var-copyright: "\f1f9"; 200 | @fa-var-creative-commons: "\f25e"; 201 | @fa-var-credit-card: "\f09d"; 202 | @fa-var-credit-card-alt: "\f283"; 203 | @fa-var-crop: "\f125"; 204 | @fa-var-crosshairs: "\f05b"; 205 | @fa-var-css3: "\f13c"; 206 | @fa-var-cube: "\f1b2"; 207 | @fa-var-cubes: "\f1b3"; 208 | @fa-var-cut: "\f0c4"; 209 | @fa-var-cutlery: "\f0f5"; 210 | @fa-var-dashboard: "\f0e4"; 211 | @fa-var-dashcube: "\f210"; 212 | @fa-var-database: "\f1c0"; 213 | @fa-var-deaf: "\f2a4"; 214 | @fa-var-deafness: "\f2a4"; 215 | @fa-var-dedent: "\f03b"; 216 | @fa-var-delicious: "\f1a5"; 217 | @fa-var-desktop: "\f108"; 218 | @fa-var-deviantart: "\f1bd"; 219 | @fa-var-diamond: "\f219"; 220 | @fa-var-digg: "\f1a6"; 221 | @fa-var-dollar: "\f155"; 222 | @fa-var-dot-circle-o: "\f192"; 223 | @fa-var-download: "\f019"; 224 | @fa-var-dribbble: "\f17d"; 225 | @fa-var-drivers-license: "\f2c2"; 226 | @fa-var-drivers-license-o: "\f2c3"; 227 | @fa-var-dropbox: "\f16b"; 228 | @fa-var-drupal: "\f1a9"; 229 | @fa-var-edge: "\f282"; 230 | @fa-var-edit: "\f044"; 231 | @fa-var-eercast: "\f2da"; 232 | @fa-var-eject: "\f052"; 233 | @fa-var-ellipsis-h: "\f141"; 234 | @fa-var-ellipsis-v: "\f142"; 235 | @fa-var-empire: "\f1d1"; 236 | @fa-var-envelope: "\f0e0"; 237 | @fa-var-envelope-o: "\f003"; 238 | @fa-var-envelope-open: "\f2b6"; 239 | @fa-var-envelope-open-o: "\f2b7"; 240 | @fa-var-envelope-square: "\f199"; 241 | @fa-var-envira: "\f299"; 242 | @fa-var-eraser: "\f12d"; 243 | @fa-var-etsy: "\f2d7"; 244 | @fa-var-eur: "\f153"; 245 | @fa-var-euro: "\f153"; 246 | @fa-var-exchange: "\f0ec"; 247 | @fa-var-exclamation: "\f12a"; 248 | @fa-var-exclamation-circle: "\f06a"; 249 | @fa-var-exclamation-triangle: "\f071"; 250 | @fa-var-expand: "\f065"; 251 | @fa-var-expeditedssl: "\f23e"; 252 | @fa-var-external-link: "\f08e"; 253 | @fa-var-external-link-square: "\f14c"; 254 | @fa-var-eye: "\f06e"; 255 | @fa-var-eye-slash: "\f070"; 256 | @fa-var-eyedropper: "\f1fb"; 257 | @fa-var-fa: "\f2b4"; 258 | @fa-var-facebook: "\f09a"; 259 | @fa-var-facebook-f: "\f09a"; 260 | @fa-var-facebook-official: "\f230"; 261 | @fa-var-facebook-square: "\f082"; 262 | @fa-var-fast-backward: "\f049"; 263 | @fa-var-fast-forward: "\f050"; 264 | @fa-var-fax: "\f1ac"; 265 | @fa-var-feed: "\f09e"; 266 | @fa-var-female: "\f182"; 267 | @fa-var-fighter-jet: "\f0fb"; 268 | @fa-var-file: "\f15b"; 269 | @fa-var-file-archive-o: "\f1c6"; 270 | @fa-var-file-audio-o: "\f1c7"; 271 | @fa-var-file-code-o: "\f1c9"; 272 | @fa-var-file-excel-o: "\f1c3"; 273 | @fa-var-file-image-o: "\f1c5"; 274 | @fa-var-file-movie-o: "\f1c8"; 275 | @fa-var-file-o: "\f016"; 276 | @fa-var-file-pdf-o: "\f1c1"; 277 | @fa-var-file-photo-o: "\f1c5"; 278 | @fa-var-file-picture-o: "\f1c5"; 279 | @fa-var-file-powerpoint-o: "\f1c4"; 280 | @fa-var-file-sound-o: "\f1c7"; 281 | @fa-var-file-text: "\f15c"; 282 | @fa-var-file-text-o: "\f0f6"; 283 | @fa-var-file-video-o: "\f1c8"; 284 | @fa-var-file-word-o: "\f1c2"; 285 | @fa-var-file-zip-o: "\f1c6"; 286 | @fa-var-files-o: "\f0c5"; 287 | @fa-var-film: "\f008"; 288 | @fa-var-filter: "\f0b0"; 289 | @fa-var-fire: "\f06d"; 290 | @fa-var-fire-extinguisher: "\f134"; 291 | @fa-var-firefox: "\f269"; 292 | @fa-var-first-order: "\f2b0"; 293 | @fa-var-flag: "\f024"; 294 | @fa-var-flag-checkered: "\f11e"; 295 | @fa-var-flag-o: "\f11d"; 296 | @fa-var-flash: "\f0e7"; 297 | @fa-var-flask: "\f0c3"; 298 | @fa-var-flickr: "\f16e"; 299 | @fa-var-floppy-o: "\f0c7"; 300 | @fa-var-folder: "\f07b"; 301 | @fa-var-folder-o: "\f114"; 302 | @fa-var-folder-open: "\f07c"; 303 | @fa-var-folder-open-o: "\f115"; 304 | @fa-var-font: "\f031"; 305 | @fa-var-font-awesome: "\f2b4"; 306 | @fa-var-fonticons: "\f280"; 307 | @fa-var-fort-awesome: "\f286"; 308 | @fa-var-forumbee: "\f211"; 309 | @fa-var-forward: "\f04e"; 310 | @fa-var-foursquare: "\f180"; 311 | @fa-var-free-code-camp: "\f2c5"; 312 | @fa-var-frown-o: "\f119"; 313 | @fa-var-futbol-o: "\f1e3"; 314 | @fa-var-gamepad: "\f11b"; 315 | @fa-var-gavel: "\f0e3"; 316 | @fa-var-gbp: "\f154"; 317 | @fa-var-ge: "\f1d1"; 318 | @fa-var-gear: "\f013"; 319 | @fa-var-gears: "\f085"; 320 | @fa-var-genderless: "\f22d"; 321 | @fa-var-get-pocket: "\f265"; 322 | @fa-var-gg: "\f260"; 323 | @fa-var-gg-circle: "\f261"; 324 | @fa-var-gift: "\f06b"; 325 | @fa-var-git: "\f1d3"; 326 | @fa-var-git-square: "\f1d2"; 327 | @fa-var-github: "\f09b"; 328 | @fa-var-github-alt: "\f113"; 329 | @fa-var-github-square: "\f092"; 330 | @fa-var-gitlab: "\f296"; 331 | @fa-var-gittip: "\f184"; 332 | @fa-var-glass: "\f000"; 333 | @fa-var-glide: "\f2a5"; 334 | @fa-var-glide-g: "\f2a6"; 335 | @fa-var-globe: "\f0ac"; 336 | @fa-var-google: "\f1a0"; 337 | @fa-var-google-plus: "\f0d5"; 338 | @fa-var-google-plus-circle: "\f2b3"; 339 | @fa-var-google-plus-official: "\f2b3"; 340 | @fa-var-google-plus-square: "\f0d4"; 341 | @fa-var-google-wallet: "\f1ee"; 342 | @fa-var-graduation-cap: "\f19d"; 343 | @fa-var-gratipay: "\f184"; 344 | @fa-var-grav: "\f2d6"; 345 | @fa-var-group: "\f0c0"; 346 | @fa-var-h-square: "\f0fd"; 347 | @fa-var-hacker-news: "\f1d4"; 348 | @fa-var-hand-grab-o: "\f255"; 349 | @fa-var-hand-lizard-o: "\f258"; 350 | @fa-var-hand-o-down: "\f0a7"; 351 | @fa-var-hand-o-left: "\f0a5"; 352 | @fa-var-hand-o-right: "\f0a4"; 353 | @fa-var-hand-o-up: "\f0a6"; 354 | @fa-var-hand-paper-o: "\f256"; 355 | @fa-var-hand-peace-o: "\f25b"; 356 | @fa-var-hand-pointer-o: "\f25a"; 357 | @fa-var-hand-rock-o: "\f255"; 358 | @fa-var-hand-scissors-o: "\f257"; 359 | @fa-var-hand-spock-o: "\f259"; 360 | @fa-var-hand-stop-o: "\f256"; 361 | @fa-var-handshake-o: "\f2b5"; 362 | @fa-var-hard-of-hearing: "\f2a4"; 363 | @fa-var-hashtag: "\f292"; 364 | @fa-var-hdd-o: "\f0a0"; 365 | @fa-var-header: "\f1dc"; 366 | @fa-var-headphones: "\f025"; 367 | @fa-var-heart: "\f004"; 368 | @fa-var-heart-o: "\f08a"; 369 | @fa-var-heartbeat: "\f21e"; 370 | @fa-var-history: "\f1da"; 371 | @fa-var-home: "\f015"; 372 | @fa-var-hospital-o: "\f0f8"; 373 | @fa-var-hotel: "\f236"; 374 | @fa-var-hourglass: "\f254"; 375 | @fa-var-hourglass-1: "\f251"; 376 | @fa-var-hourglass-2: "\f252"; 377 | @fa-var-hourglass-3: "\f253"; 378 | @fa-var-hourglass-end: "\f253"; 379 | @fa-var-hourglass-half: "\f252"; 380 | @fa-var-hourglass-o: "\f250"; 381 | @fa-var-hourglass-start: "\f251"; 382 | @fa-var-houzz: "\f27c"; 383 | @fa-var-html5: "\f13b"; 384 | @fa-var-i-cursor: "\f246"; 385 | @fa-var-id-badge: "\f2c1"; 386 | @fa-var-id-card: "\f2c2"; 387 | @fa-var-id-card-o: "\f2c3"; 388 | @fa-var-ils: "\f20b"; 389 | @fa-var-image: "\f03e"; 390 | @fa-var-imdb: "\f2d8"; 391 | @fa-var-inbox: "\f01c"; 392 | @fa-var-indent: "\f03c"; 393 | @fa-var-industry: "\f275"; 394 | @fa-var-info: "\f129"; 395 | @fa-var-info-circle: "\f05a"; 396 | @fa-var-inr: "\f156"; 397 | @fa-var-instagram: "\f16d"; 398 | @fa-var-institution: "\f19c"; 399 | @fa-var-internet-explorer: "\f26b"; 400 | @fa-var-intersex: "\f224"; 401 | @fa-var-ioxhost: "\f208"; 402 | @fa-var-italic: "\f033"; 403 | @fa-var-joomla: "\f1aa"; 404 | @fa-var-jpy: "\f157"; 405 | @fa-var-jsfiddle: "\f1cc"; 406 | @fa-var-key: "\f084"; 407 | @fa-var-keyboard-o: "\f11c"; 408 | @fa-var-krw: "\f159"; 409 | @fa-var-language: "\f1ab"; 410 | @fa-var-laptop: "\f109"; 411 | @fa-var-lastfm: "\f202"; 412 | @fa-var-lastfm-square: "\f203"; 413 | @fa-var-leaf: "\f06c"; 414 | @fa-var-leanpub: "\f212"; 415 | @fa-var-legal: "\f0e3"; 416 | @fa-var-lemon-o: "\f094"; 417 | @fa-var-level-down: "\f149"; 418 | @fa-var-level-up: "\f148"; 419 | @fa-var-life-bouy: "\f1cd"; 420 | @fa-var-life-buoy: "\f1cd"; 421 | @fa-var-life-ring: "\f1cd"; 422 | @fa-var-life-saver: "\f1cd"; 423 | @fa-var-lightbulb-o: "\f0eb"; 424 | @fa-var-line-chart: "\f201"; 425 | @fa-var-link: "\f0c1"; 426 | @fa-var-linkedin: "\f0e1"; 427 | @fa-var-linkedin-square: "\f08c"; 428 | @fa-var-linode: "\f2b8"; 429 | @fa-var-linux: "\f17c"; 430 | @fa-var-list: "\f03a"; 431 | @fa-var-list-alt: "\f022"; 432 | @fa-var-list-ol: "\f0cb"; 433 | @fa-var-list-ul: "\f0ca"; 434 | @fa-var-location-arrow: "\f124"; 435 | @fa-var-lock: "\f023"; 436 | @fa-var-long-arrow-down: "\f175"; 437 | @fa-var-long-arrow-left: "\f177"; 438 | @fa-var-long-arrow-right: "\f178"; 439 | @fa-var-long-arrow-up: "\f176"; 440 | @fa-var-low-vision: "\f2a8"; 441 | @fa-var-magic: "\f0d0"; 442 | @fa-var-magnet: "\f076"; 443 | @fa-var-mail-forward: "\f064"; 444 | @fa-var-mail-reply: "\f112"; 445 | @fa-var-mail-reply-all: "\f122"; 446 | @fa-var-male: "\f183"; 447 | @fa-var-map: "\f279"; 448 | @fa-var-map-marker: "\f041"; 449 | @fa-var-map-o: "\f278"; 450 | @fa-var-map-pin: "\f276"; 451 | @fa-var-map-signs: "\f277"; 452 | @fa-var-mars: "\f222"; 453 | @fa-var-mars-double: "\f227"; 454 | @fa-var-mars-stroke: "\f229"; 455 | @fa-var-mars-stroke-h: "\f22b"; 456 | @fa-var-mars-stroke-v: "\f22a"; 457 | @fa-var-maxcdn: "\f136"; 458 | @fa-var-meanpath: "\f20c"; 459 | @fa-var-medium: "\f23a"; 460 | @fa-var-medkit: "\f0fa"; 461 | @fa-var-meetup: "\f2e0"; 462 | @fa-var-meh-o: "\f11a"; 463 | @fa-var-mercury: "\f223"; 464 | @fa-var-microchip: "\f2db"; 465 | @fa-var-microphone: "\f130"; 466 | @fa-var-microphone-slash: "\f131"; 467 | @fa-var-minus: "\f068"; 468 | @fa-var-minus-circle: "\f056"; 469 | @fa-var-minus-square: "\f146"; 470 | @fa-var-minus-square-o: "\f147"; 471 | @fa-var-mixcloud: "\f289"; 472 | @fa-var-mobile: "\f10b"; 473 | @fa-var-mobile-phone: "\f10b"; 474 | @fa-var-modx: "\f285"; 475 | @fa-var-money: "\f0d6"; 476 | @fa-var-moon-o: "\f186"; 477 | @fa-var-mortar-board: "\f19d"; 478 | @fa-var-motorcycle: "\f21c"; 479 | @fa-var-mouse-pointer: "\f245"; 480 | @fa-var-music: "\f001"; 481 | @fa-var-navicon: "\f0c9"; 482 | @fa-var-neuter: "\f22c"; 483 | @fa-var-newspaper-o: "\f1ea"; 484 | @fa-var-object-group: "\f247"; 485 | @fa-var-object-ungroup: "\f248"; 486 | @fa-var-odnoklassniki: "\f263"; 487 | @fa-var-odnoklassniki-square: "\f264"; 488 | @fa-var-opencart: "\f23d"; 489 | @fa-var-openid: "\f19b"; 490 | @fa-var-opera: "\f26a"; 491 | @fa-var-optin-monster: "\f23c"; 492 | @fa-var-outdent: "\f03b"; 493 | @fa-var-pagelines: "\f18c"; 494 | @fa-var-paint-brush: "\f1fc"; 495 | @fa-var-paper-plane: "\f1d8"; 496 | @fa-var-paper-plane-o: "\f1d9"; 497 | @fa-var-paperclip: "\f0c6"; 498 | @fa-var-paragraph: "\f1dd"; 499 | @fa-var-paste: "\f0ea"; 500 | @fa-var-pause: "\f04c"; 501 | @fa-var-pause-circle: "\f28b"; 502 | @fa-var-pause-circle-o: "\f28c"; 503 | @fa-var-paw: "\f1b0"; 504 | @fa-var-paypal: "\f1ed"; 505 | @fa-var-pencil: "\f040"; 506 | @fa-var-pencil-square: "\f14b"; 507 | @fa-var-pencil-square-o: "\f044"; 508 | @fa-var-percent: "\f295"; 509 | @fa-var-phone: "\f095"; 510 | @fa-var-phone-square: "\f098"; 511 | @fa-var-photo: "\f03e"; 512 | @fa-var-picture-o: "\f03e"; 513 | @fa-var-pie-chart: "\f200"; 514 | @fa-var-pied-piper: "\f2ae"; 515 | @fa-var-pied-piper-alt: "\f1a8"; 516 | @fa-var-pied-piper-pp: "\f1a7"; 517 | @fa-var-pinterest: "\f0d2"; 518 | @fa-var-pinterest-p: "\f231"; 519 | @fa-var-pinterest-square: "\f0d3"; 520 | @fa-var-plane: "\f072"; 521 | @fa-var-play: "\f04b"; 522 | @fa-var-play-circle: "\f144"; 523 | @fa-var-play-circle-o: "\f01d"; 524 | @fa-var-plug: "\f1e6"; 525 | @fa-var-plus: "\f067"; 526 | @fa-var-plus-circle: "\f055"; 527 | @fa-var-plus-square: "\f0fe"; 528 | @fa-var-plus-square-o: "\f196"; 529 | @fa-var-podcast: "\f2ce"; 530 | @fa-var-power-off: "\f011"; 531 | @fa-var-print: "\f02f"; 532 | @fa-var-product-hunt: "\f288"; 533 | @fa-var-puzzle-piece: "\f12e"; 534 | @fa-var-qq: "\f1d6"; 535 | @fa-var-qrcode: "\f029"; 536 | @fa-var-question: "\f128"; 537 | @fa-var-question-circle: "\f059"; 538 | @fa-var-question-circle-o: "\f29c"; 539 | @fa-var-quora: "\f2c4"; 540 | @fa-var-quote-left: "\f10d"; 541 | @fa-var-quote-right: "\f10e"; 542 | @fa-var-ra: "\f1d0"; 543 | @fa-var-random: "\f074"; 544 | @fa-var-ravelry: "\f2d9"; 545 | @fa-var-rebel: "\f1d0"; 546 | @fa-var-recycle: "\f1b8"; 547 | @fa-var-reddit: "\f1a1"; 548 | @fa-var-reddit-alien: "\f281"; 549 | @fa-var-reddit-square: "\f1a2"; 550 | @fa-var-refresh: "\f021"; 551 | @fa-var-registered: "\f25d"; 552 | @fa-var-remove: "\f00d"; 553 | @fa-var-renren: "\f18b"; 554 | @fa-var-reorder: "\f0c9"; 555 | @fa-var-repeat: "\f01e"; 556 | @fa-var-reply: "\f112"; 557 | @fa-var-reply-all: "\f122"; 558 | @fa-var-resistance: "\f1d0"; 559 | @fa-var-retweet: "\f079"; 560 | @fa-var-rmb: "\f157"; 561 | @fa-var-road: "\f018"; 562 | @fa-var-rocket: "\f135"; 563 | @fa-var-rotate-left: "\f0e2"; 564 | @fa-var-rotate-right: "\f01e"; 565 | @fa-var-rouble: "\f158"; 566 | @fa-var-rss: "\f09e"; 567 | @fa-var-rss-square: "\f143"; 568 | @fa-var-rub: "\f158"; 569 | @fa-var-ruble: "\f158"; 570 | @fa-var-rupee: "\f156"; 571 | @fa-var-s15: "\f2cd"; 572 | @fa-var-safari: "\f267"; 573 | @fa-var-save: "\f0c7"; 574 | @fa-var-scissors: "\f0c4"; 575 | @fa-var-scribd: "\f28a"; 576 | @fa-var-search: "\f002"; 577 | @fa-var-search-minus: "\f010"; 578 | @fa-var-search-plus: "\f00e"; 579 | @fa-var-sellsy: "\f213"; 580 | @fa-var-send: "\f1d8"; 581 | @fa-var-send-o: "\f1d9"; 582 | @fa-var-server: "\f233"; 583 | @fa-var-share: "\f064"; 584 | @fa-var-share-alt: "\f1e0"; 585 | @fa-var-share-alt-square: "\f1e1"; 586 | @fa-var-share-square: "\f14d"; 587 | @fa-var-share-square-o: "\f045"; 588 | @fa-var-shekel: "\f20b"; 589 | @fa-var-sheqel: "\f20b"; 590 | @fa-var-shield: "\f132"; 591 | @fa-var-ship: "\f21a"; 592 | @fa-var-shirtsinbulk: "\f214"; 593 | @fa-var-shopping-bag: "\f290"; 594 | @fa-var-shopping-basket: "\f291"; 595 | @fa-var-shopping-cart: "\f07a"; 596 | @fa-var-shower: "\f2cc"; 597 | @fa-var-sign-in: "\f090"; 598 | @fa-var-sign-language: "\f2a7"; 599 | @fa-var-sign-out: "\f08b"; 600 | @fa-var-signal: "\f012"; 601 | @fa-var-signing: "\f2a7"; 602 | @fa-var-simplybuilt: "\f215"; 603 | @fa-var-sitemap: "\f0e8"; 604 | @fa-var-skyatlas: "\f216"; 605 | @fa-var-skype: "\f17e"; 606 | @fa-var-slack: "\f198"; 607 | @fa-var-sliders: "\f1de"; 608 | @fa-var-slideshare: "\f1e7"; 609 | @fa-var-smile-o: "\f118"; 610 | @fa-var-snapchat: "\f2ab"; 611 | @fa-var-snapchat-ghost: "\f2ac"; 612 | @fa-var-snapchat-square: "\f2ad"; 613 | @fa-var-snowflake-o: "\f2dc"; 614 | @fa-var-soccer-ball-o: "\f1e3"; 615 | @fa-var-sort: "\f0dc"; 616 | @fa-var-sort-alpha-asc: "\f15d"; 617 | @fa-var-sort-alpha-desc: "\f15e"; 618 | @fa-var-sort-amount-asc: "\f160"; 619 | @fa-var-sort-amount-desc: "\f161"; 620 | @fa-var-sort-asc: "\f0de"; 621 | @fa-var-sort-desc: "\f0dd"; 622 | @fa-var-sort-down: "\f0dd"; 623 | @fa-var-sort-numeric-asc: "\f162"; 624 | @fa-var-sort-numeric-desc: "\f163"; 625 | @fa-var-sort-up: "\f0de"; 626 | @fa-var-soundcloud: "\f1be"; 627 | @fa-var-space-shuttle: "\f197"; 628 | @fa-var-spinner: "\f110"; 629 | @fa-var-spoon: "\f1b1"; 630 | @fa-var-spotify: "\f1bc"; 631 | @fa-var-square: "\f0c8"; 632 | @fa-var-square-o: "\f096"; 633 | @fa-var-stack-exchange: "\f18d"; 634 | @fa-var-stack-overflow: "\f16c"; 635 | @fa-var-star: "\f005"; 636 | @fa-var-star-half: "\f089"; 637 | @fa-var-star-half-empty: "\f123"; 638 | @fa-var-star-half-full: "\f123"; 639 | @fa-var-star-half-o: "\f123"; 640 | @fa-var-star-o: "\f006"; 641 | @fa-var-steam: "\f1b6"; 642 | @fa-var-steam-square: "\f1b7"; 643 | @fa-var-step-backward: "\f048"; 644 | @fa-var-step-forward: "\f051"; 645 | @fa-var-stethoscope: "\f0f1"; 646 | @fa-var-sticky-note: "\f249"; 647 | @fa-var-sticky-note-o: "\f24a"; 648 | @fa-var-stop: "\f04d"; 649 | @fa-var-stop-circle: "\f28d"; 650 | @fa-var-stop-circle-o: "\f28e"; 651 | @fa-var-street-view: "\f21d"; 652 | @fa-var-strikethrough: "\f0cc"; 653 | @fa-var-stumbleupon: "\f1a4"; 654 | @fa-var-stumbleupon-circle: "\f1a3"; 655 | @fa-var-subscript: "\f12c"; 656 | @fa-var-subway: "\f239"; 657 | @fa-var-suitcase: "\f0f2"; 658 | @fa-var-sun-o: "\f185"; 659 | @fa-var-superpowers: "\f2dd"; 660 | @fa-var-superscript: "\f12b"; 661 | @fa-var-support: "\f1cd"; 662 | @fa-var-table: "\f0ce"; 663 | @fa-var-tablet: "\f10a"; 664 | @fa-var-tachometer: "\f0e4"; 665 | @fa-var-tag: "\f02b"; 666 | @fa-var-tags: "\f02c"; 667 | @fa-var-tasks: "\f0ae"; 668 | @fa-var-taxi: "\f1ba"; 669 | @fa-var-telegram: "\f2c6"; 670 | @fa-var-television: "\f26c"; 671 | @fa-var-tencent-weibo: "\f1d5"; 672 | @fa-var-terminal: "\f120"; 673 | @fa-var-text-height: "\f034"; 674 | @fa-var-text-width: "\f035"; 675 | @fa-var-th: "\f00a"; 676 | @fa-var-th-large: "\f009"; 677 | @fa-var-th-list: "\f00b"; 678 | @fa-var-themeisle: "\f2b2"; 679 | @fa-var-thermometer: "\f2c7"; 680 | @fa-var-thermometer-0: "\f2cb"; 681 | @fa-var-thermometer-1: "\f2ca"; 682 | @fa-var-thermometer-2: "\f2c9"; 683 | @fa-var-thermometer-3: "\f2c8"; 684 | @fa-var-thermometer-4: "\f2c7"; 685 | @fa-var-thermometer-empty: "\f2cb"; 686 | @fa-var-thermometer-full: "\f2c7"; 687 | @fa-var-thermometer-half: "\f2c9"; 688 | @fa-var-thermometer-quarter: "\f2ca"; 689 | @fa-var-thermometer-three-quarters: "\f2c8"; 690 | @fa-var-thumb-tack: "\f08d"; 691 | @fa-var-thumbs-down: "\f165"; 692 | @fa-var-thumbs-o-down: "\f088"; 693 | @fa-var-thumbs-o-up: "\f087"; 694 | @fa-var-thumbs-up: "\f164"; 695 | @fa-var-ticket: "\f145"; 696 | @fa-var-times: "\f00d"; 697 | @fa-var-times-circle: "\f057"; 698 | @fa-var-times-circle-o: "\f05c"; 699 | @fa-var-times-rectangle: "\f2d3"; 700 | @fa-var-times-rectangle-o: "\f2d4"; 701 | @fa-var-tint: "\f043"; 702 | @fa-var-toggle-down: "\f150"; 703 | @fa-var-toggle-left: "\f191"; 704 | @fa-var-toggle-off: "\f204"; 705 | @fa-var-toggle-on: "\f205"; 706 | @fa-var-toggle-right: "\f152"; 707 | @fa-var-toggle-up: "\f151"; 708 | @fa-var-trademark: "\f25c"; 709 | @fa-var-train: "\f238"; 710 | @fa-var-transgender: "\f224"; 711 | @fa-var-transgender-alt: "\f225"; 712 | @fa-var-trash: "\f1f8"; 713 | @fa-var-trash-o: "\f014"; 714 | @fa-var-tree: "\f1bb"; 715 | @fa-var-trello: "\f181"; 716 | @fa-var-tripadvisor: "\f262"; 717 | @fa-var-trophy: "\f091"; 718 | @fa-var-truck: "\f0d1"; 719 | @fa-var-try: "\f195"; 720 | @fa-var-tty: "\f1e4"; 721 | @fa-var-tumblr: "\f173"; 722 | @fa-var-tumblr-square: "\f174"; 723 | @fa-var-turkish-lira: "\f195"; 724 | @fa-var-tv: "\f26c"; 725 | @fa-var-twitch: "\f1e8"; 726 | @fa-var-twitter: "\f099"; 727 | @fa-var-twitter-square: "\f081"; 728 | @fa-var-umbrella: "\f0e9"; 729 | @fa-var-underline: "\f0cd"; 730 | @fa-var-undo: "\f0e2"; 731 | @fa-var-universal-access: "\f29a"; 732 | @fa-var-university: "\f19c"; 733 | @fa-var-unlink: "\f127"; 734 | @fa-var-unlock: "\f09c"; 735 | @fa-var-unlock-alt: "\f13e"; 736 | @fa-var-unsorted: "\f0dc"; 737 | @fa-var-upload: "\f093"; 738 | @fa-var-usb: "\f287"; 739 | @fa-var-usd: "\f155"; 740 | @fa-var-user: "\f007"; 741 | @fa-var-user-circle: "\f2bd"; 742 | @fa-var-user-circle-o: "\f2be"; 743 | @fa-var-user-md: "\f0f0"; 744 | @fa-var-user-o: "\f2c0"; 745 | @fa-var-user-plus: "\f234"; 746 | @fa-var-user-secret: "\f21b"; 747 | @fa-var-user-times: "\f235"; 748 | @fa-var-users: "\f0c0"; 749 | @fa-var-vcard: "\f2bb"; 750 | @fa-var-vcard-o: "\f2bc"; 751 | @fa-var-venus: "\f221"; 752 | @fa-var-venus-double: "\f226"; 753 | @fa-var-venus-mars: "\f228"; 754 | @fa-var-viacoin: "\f237"; 755 | @fa-var-viadeo: "\f2a9"; 756 | @fa-var-viadeo-square: "\f2aa"; 757 | @fa-var-video-camera: "\f03d"; 758 | @fa-var-vimeo: "\f27d"; 759 | @fa-var-vimeo-square: "\f194"; 760 | @fa-var-vine: "\f1ca"; 761 | @fa-var-vk: "\f189"; 762 | @fa-var-volume-control-phone: "\f2a0"; 763 | @fa-var-volume-down: "\f027"; 764 | @fa-var-volume-off: "\f026"; 765 | @fa-var-volume-up: "\f028"; 766 | @fa-var-warning: "\f071"; 767 | @fa-var-wechat: "\f1d7"; 768 | @fa-var-weibo: "\f18a"; 769 | @fa-var-weixin: "\f1d7"; 770 | @fa-var-whatsapp: "\f232"; 771 | @fa-var-wheelchair: "\f193"; 772 | @fa-var-wheelchair-alt: "\f29b"; 773 | @fa-var-wifi: "\f1eb"; 774 | @fa-var-wikipedia-w: "\f266"; 775 | @fa-var-window-close: "\f2d3"; 776 | @fa-var-window-close-o: "\f2d4"; 777 | @fa-var-window-maximize: "\f2d0"; 778 | @fa-var-window-minimize: "\f2d1"; 779 | @fa-var-window-restore: "\f2d2"; 780 | @fa-var-windows: "\f17a"; 781 | @fa-var-won: "\f159"; 782 | @fa-var-wordpress: "\f19a"; 783 | @fa-var-wpbeginner: "\f297"; 784 | @fa-var-wpexplorer: "\f2de"; 785 | @fa-var-wpforms: "\f298"; 786 | @fa-var-wrench: "\f0ad"; 787 | @fa-var-xing: "\f168"; 788 | @fa-var-xing-square: "\f169"; 789 | @fa-var-y-combinator: "\f23b"; 790 | @fa-var-y-combinator-square: "\f1d4"; 791 | @fa-var-yahoo: "\f19e"; 792 | @fa-var-yc: "\f23b"; 793 | @fa-var-yc-square: "\f1d4"; 794 | @fa-var-yelp: "\f1e9"; 795 | @fa-var-yen: "\f157"; 796 | @fa-var-yoast: "\f2b1"; 797 | @fa-var-youtube: "\f167"; 798 | @fa-var-youtube-play: "\f16a"; 799 | @fa-var-youtube-square: "\f166"; 800 | 801 | -------------------------------------------------------------------------------- /src/font-awesome/scss/_animated.scss: -------------------------------------------------------------------------------- 1 | // Spinning Icons 2 | // -------------------------- 3 | 4 | .#{$fa-css-prefix}-spin { 5 | -webkit-animation: fa-spin 2s infinite linear; 6 | animation: fa-spin 2s infinite linear; 7 | } 8 | 9 | .#{$fa-css-prefix}-pulse { 10 | -webkit-animation: fa-spin 1s infinite steps(8); 11 | animation: fa-spin 1s infinite steps(8); 12 | } 13 | 14 | @-webkit-keyframes fa-spin { 15 | 0% { 16 | -webkit-transform: rotate(0deg); 17 | transform: rotate(0deg); 18 | } 19 | 100% { 20 | -webkit-transform: rotate(359deg); 21 | transform: rotate(359deg); 22 | } 23 | } 24 | 25 | @keyframes fa-spin { 26 | 0% { 27 | -webkit-transform: rotate(0deg); 28 | transform: rotate(0deg); 29 | } 30 | 100% { 31 | -webkit-transform: rotate(359deg); 32 | transform: rotate(359deg); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/font-awesome/scss/_bordered-pulled.scss: -------------------------------------------------------------------------------- 1 | // Bordered & Pulled 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix}-border { 5 | padding: .2em .25em .15em; 6 | border: solid .08em $fa-border-color; 7 | border-radius: .1em; 8 | } 9 | 10 | .#{$fa-css-prefix}-pull-left { float: left; } 11 | .#{$fa-css-prefix}-pull-right { float: right; } 12 | 13 | .#{$fa-css-prefix} { 14 | &.#{$fa-css-prefix}-pull-left { margin-right: .3em; } 15 | &.#{$fa-css-prefix}-pull-right { margin-left: .3em; } 16 | } 17 | 18 | /* Deprecated as of 4.4.0 */ 19 | .pull-right { float: right; } 20 | .pull-left { float: left; } 21 | 22 | .#{$fa-css-prefix} { 23 | &.pull-left { margin-right: .3em; } 24 | &.pull-right { margin-left: .3em; } 25 | } 26 | -------------------------------------------------------------------------------- /src/font-awesome/scss/_core.scss: -------------------------------------------------------------------------------- 1 | // Base Class Definition 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix} { 5 | display: inline-block; 6 | font: normal normal normal #{$fa-font-size-base}/#{$fa-line-height-base} FontAwesome; // shortening font declaration 7 | font-size: inherit; // can't have font-size inherit on line above, so need to override 8 | text-rendering: auto; // optimizelegibility throws things off #1094 9 | -webkit-font-smoothing: antialiased; 10 | -moz-osx-font-smoothing: grayscale; 11 | 12 | } 13 | -------------------------------------------------------------------------------- /src/font-awesome/scss/_fixed-width.scss: -------------------------------------------------------------------------------- 1 | // Fixed Width Icons 2 | // ------------------------- 3 | .#{$fa-css-prefix}-fw { 4 | width: (18em / 14); 5 | text-align: center; 6 | } 7 | -------------------------------------------------------------------------------- /src/font-awesome/scss/_larger.scss: -------------------------------------------------------------------------------- 1 | // Icon Sizes 2 | // ------------------------- 3 | 4 | /* makes the font 33% larger relative to the icon container */ 5 | .#{$fa-css-prefix}-lg { 6 | font-size: (4em / 3); 7 | line-height: (3em / 4); 8 | vertical-align: -15%; 9 | } 10 | .#{$fa-css-prefix}-2x { font-size: 2em; } 11 | .#{$fa-css-prefix}-3x { font-size: 3em; } 12 | .#{$fa-css-prefix}-4x { font-size: 4em; } 13 | .#{$fa-css-prefix}-5x { font-size: 5em; } 14 | -------------------------------------------------------------------------------- /src/font-awesome/scss/_list.scss: -------------------------------------------------------------------------------- 1 | // List Icons 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix}-ul { 5 | padding-left: 0; 6 | margin-left: $fa-li-width; 7 | list-style-type: none; 8 | > li { position: relative; } 9 | } 10 | .#{$fa-css-prefix}-li { 11 | position: absolute; 12 | left: -$fa-li-width; 13 | width: $fa-li-width; 14 | top: (2em / 14); 15 | text-align: center; 16 | &.#{$fa-css-prefix}-lg { 17 | left: -$fa-li-width + (4em / 14); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/font-awesome/scss/_mixins.scss: -------------------------------------------------------------------------------- 1 | // Mixins 2 | // -------------------------- 3 | 4 | @mixin fa-icon() { 5 | display: inline-block; 6 | font: normal normal normal #{$fa-font-size-base}/#{$fa-line-height-base} FontAwesome; // shortening font declaration 7 | font-size: inherit; // can't have font-size inherit on line above, so need to override 8 | text-rendering: auto; // optimizelegibility throws things off #1094 9 | -webkit-font-smoothing: antialiased; 10 | -moz-osx-font-smoothing: grayscale; 11 | 12 | } 13 | 14 | @mixin fa-icon-rotate($degrees, $rotation) { 15 | -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=#{$rotation})"; 16 | -webkit-transform: rotate($degrees); 17 | -ms-transform: rotate($degrees); 18 | transform: rotate($degrees); 19 | } 20 | 21 | @mixin fa-icon-flip($horiz, $vert, $rotation) { 22 | -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=#{$rotation}, mirror=1)"; 23 | -webkit-transform: scale($horiz, $vert); 24 | -ms-transform: scale($horiz, $vert); 25 | transform: scale($horiz, $vert); 26 | } 27 | 28 | 29 | // Only display content to screen readers. A la Bootstrap 4. 30 | // 31 | // See: http://a11yproject.com/posts/how-to-hide-content/ 32 | 33 | @mixin sr-only { 34 | position: absolute; 35 | width: 1px; 36 | height: 1px; 37 | padding: 0; 38 | margin: -1px; 39 | overflow: hidden; 40 | clip: rect(0,0,0,0); 41 | border: 0; 42 | } 43 | 44 | // Use in conjunction with .sr-only to only display content when it's focused. 45 | // 46 | // Useful for "Skip to main content" links; see http://www.w3.org/TR/2013/NOTE-WCAG20-TECHS-20130905/G1 47 | // 48 | // Credit: HTML5 Boilerplate 49 | 50 | @mixin sr-only-focusable { 51 | &:active, 52 | &:focus { 53 | position: static; 54 | width: auto; 55 | height: auto; 56 | margin: 0; 57 | overflow: visible; 58 | clip: auto; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/font-awesome/scss/_path.scss: -------------------------------------------------------------------------------- 1 | /* FONT PATH 2 | * -------------------------- */ 3 | 4 | @font-face { 5 | font-family: 'FontAwesome'; 6 | src: url('#{$fa-font-path}/fontawesome-webfont.eot?v=#{$fa-version}'); 7 | src: url('#{$fa-font-path}/fontawesome-webfont.eot?#iefix&v=#{$fa-version}') format('embedded-opentype'), 8 | url('#{$fa-font-path}/fontawesome-webfont.woff2?v=#{$fa-version}') format('woff2'), 9 | url('#{$fa-font-path}/fontawesome-webfont.woff?v=#{$fa-version}') format('woff'), 10 | url('#{$fa-font-path}/fontawesome-webfont.ttf?v=#{$fa-version}') format('truetype'), 11 | url('#{$fa-font-path}/fontawesome-webfont.svg?v=#{$fa-version}#fontawesomeregular') format('svg'); 12 | // src: url('#{$fa-font-path}/FontAwesome.otf') format('opentype'); // used when developing fonts 13 | font-weight: normal; 14 | font-style: normal; 15 | } 16 | -------------------------------------------------------------------------------- /src/font-awesome/scss/_rotated-flipped.scss: -------------------------------------------------------------------------------- 1 | // Rotated & Flipped Icons 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix}-rotate-90 { @include fa-icon-rotate(90deg, 1); } 5 | .#{$fa-css-prefix}-rotate-180 { @include fa-icon-rotate(180deg, 2); } 6 | .#{$fa-css-prefix}-rotate-270 { @include fa-icon-rotate(270deg, 3); } 7 | 8 | .#{$fa-css-prefix}-flip-horizontal { @include fa-icon-flip(-1, 1, 0); } 9 | .#{$fa-css-prefix}-flip-vertical { @include fa-icon-flip(1, -1, 2); } 10 | 11 | // Hook for IE8-9 12 | // ------------------------- 13 | 14 | :root .#{$fa-css-prefix}-rotate-90, 15 | :root .#{$fa-css-prefix}-rotate-180, 16 | :root .#{$fa-css-prefix}-rotate-270, 17 | :root .#{$fa-css-prefix}-flip-horizontal, 18 | :root .#{$fa-css-prefix}-flip-vertical { 19 | filter: none; 20 | } 21 | -------------------------------------------------------------------------------- /src/font-awesome/scss/_screen-reader.scss: -------------------------------------------------------------------------------- 1 | // Screen Readers 2 | // ------------------------- 3 | 4 | .sr-only { @include sr-only(); } 5 | .sr-only-focusable { @include sr-only-focusable(); } 6 | -------------------------------------------------------------------------------- /src/font-awesome/scss/_stacked.scss: -------------------------------------------------------------------------------- 1 | // Stacked Icons 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix}-stack { 5 | position: relative; 6 | display: inline-block; 7 | width: 2em; 8 | height: 2em; 9 | line-height: 2em; 10 | vertical-align: middle; 11 | } 12 | .#{$fa-css-prefix}-stack-1x, .#{$fa-css-prefix}-stack-2x { 13 | position: absolute; 14 | left: 0; 15 | width: 100%; 16 | text-align: center; 17 | } 18 | .#{$fa-css-prefix}-stack-1x { line-height: inherit; } 19 | .#{$fa-css-prefix}-stack-2x { font-size: 2em; } 20 | .#{$fa-css-prefix}-inverse { color: $fa-inverse; } 21 | -------------------------------------------------------------------------------- /src/font-awesome/scss/_variables.scss: -------------------------------------------------------------------------------- 1 | // Variables 2 | // -------------------------- 3 | 4 | $fa-font-path: "../fonts" !default; 5 | $fa-font-size-base: 14px !default; 6 | $fa-line-height-base: 1 !default; 7 | //$fa-font-path: "//netdna.bootstrapcdn.com/font-awesome/4.7.0/fonts" !default; // for referencing Bootstrap CDN font files directly 8 | $fa-css-prefix: fa !default; 9 | $fa-version: "4.7.0" !default; 10 | $fa-border-color: #eee !default; 11 | $fa-inverse: #fff !default; 12 | $fa-li-width: (30em / 14) !default; 13 | 14 | $fa-var-500px: "\f26e"; 15 | $fa-var-address-book: "\f2b9"; 16 | $fa-var-address-book-o: "\f2ba"; 17 | $fa-var-address-card: "\f2bb"; 18 | $fa-var-address-card-o: "\f2bc"; 19 | $fa-var-adjust: "\f042"; 20 | $fa-var-adn: "\f170"; 21 | $fa-var-align-center: "\f037"; 22 | $fa-var-align-justify: "\f039"; 23 | $fa-var-align-left: "\f036"; 24 | $fa-var-align-right: "\f038"; 25 | $fa-var-amazon: "\f270"; 26 | $fa-var-ambulance: "\f0f9"; 27 | $fa-var-american-sign-language-interpreting: "\f2a3"; 28 | $fa-var-anchor: "\f13d"; 29 | $fa-var-android: "\f17b"; 30 | $fa-var-angellist: "\f209"; 31 | $fa-var-angle-double-down: "\f103"; 32 | $fa-var-angle-double-left: "\f100"; 33 | $fa-var-angle-double-right: "\f101"; 34 | $fa-var-angle-double-up: "\f102"; 35 | $fa-var-angle-down: "\f107"; 36 | $fa-var-angle-left: "\f104"; 37 | $fa-var-angle-right: "\f105"; 38 | $fa-var-angle-up: "\f106"; 39 | $fa-var-apple: "\f179"; 40 | $fa-var-archive: "\f187"; 41 | $fa-var-area-chart: "\f1fe"; 42 | $fa-var-arrow-circle-down: "\f0ab"; 43 | $fa-var-arrow-circle-left: "\f0a8"; 44 | $fa-var-arrow-circle-o-down: "\f01a"; 45 | $fa-var-arrow-circle-o-left: "\f190"; 46 | $fa-var-arrow-circle-o-right: "\f18e"; 47 | $fa-var-arrow-circle-o-up: "\f01b"; 48 | $fa-var-arrow-circle-right: "\f0a9"; 49 | $fa-var-arrow-circle-up: "\f0aa"; 50 | $fa-var-arrow-down: "\f063"; 51 | $fa-var-arrow-left: "\f060"; 52 | $fa-var-arrow-right: "\f061"; 53 | $fa-var-arrow-up: "\f062"; 54 | $fa-var-arrows: "\f047"; 55 | $fa-var-arrows-alt: "\f0b2"; 56 | $fa-var-arrows-h: "\f07e"; 57 | $fa-var-arrows-v: "\f07d"; 58 | $fa-var-asl-interpreting: "\f2a3"; 59 | $fa-var-assistive-listening-systems: "\f2a2"; 60 | $fa-var-asterisk: "\f069"; 61 | $fa-var-at: "\f1fa"; 62 | $fa-var-audio-description: "\f29e"; 63 | $fa-var-automobile: "\f1b9"; 64 | $fa-var-backward: "\f04a"; 65 | $fa-var-balance-scale: "\f24e"; 66 | $fa-var-ban: "\f05e"; 67 | $fa-var-bandcamp: "\f2d5"; 68 | $fa-var-bank: "\f19c"; 69 | $fa-var-bar-chart: "\f080"; 70 | $fa-var-bar-chart-o: "\f080"; 71 | $fa-var-barcode: "\f02a"; 72 | $fa-var-bars: "\f0c9"; 73 | $fa-var-bath: "\f2cd"; 74 | $fa-var-bathtub: "\f2cd"; 75 | $fa-var-battery: "\f240"; 76 | $fa-var-battery-0: "\f244"; 77 | $fa-var-battery-1: "\f243"; 78 | $fa-var-battery-2: "\f242"; 79 | $fa-var-battery-3: "\f241"; 80 | $fa-var-battery-4: "\f240"; 81 | $fa-var-battery-empty: "\f244"; 82 | $fa-var-battery-full: "\f240"; 83 | $fa-var-battery-half: "\f242"; 84 | $fa-var-battery-quarter: "\f243"; 85 | $fa-var-battery-three-quarters: "\f241"; 86 | $fa-var-bed: "\f236"; 87 | $fa-var-beer: "\f0fc"; 88 | $fa-var-behance: "\f1b4"; 89 | $fa-var-behance-square: "\f1b5"; 90 | $fa-var-bell: "\f0f3"; 91 | $fa-var-bell-o: "\f0a2"; 92 | $fa-var-bell-slash: "\f1f6"; 93 | $fa-var-bell-slash-o: "\f1f7"; 94 | $fa-var-bicycle: "\f206"; 95 | $fa-var-binoculars: "\f1e5"; 96 | $fa-var-birthday-cake: "\f1fd"; 97 | $fa-var-bitbucket: "\f171"; 98 | $fa-var-bitbucket-square: "\f172"; 99 | $fa-var-bitcoin: "\f15a"; 100 | $fa-var-black-tie: "\f27e"; 101 | $fa-var-blind: "\f29d"; 102 | $fa-var-bluetooth: "\f293"; 103 | $fa-var-bluetooth-b: "\f294"; 104 | $fa-var-bold: "\f032"; 105 | $fa-var-bolt: "\f0e7"; 106 | $fa-var-bomb: "\f1e2"; 107 | $fa-var-book: "\f02d"; 108 | $fa-var-bookmark: "\f02e"; 109 | $fa-var-bookmark-o: "\f097"; 110 | $fa-var-braille: "\f2a1"; 111 | $fa-var-briefcase: "\f0b1"; 112 | $fa-var-btc: "\f15a"; 113 | $fa-var-bug: "\f188"; 114 | $fa-var-building: "\f1ad"; 115 | $fa-var-building-o: "\f0f7"; 116 | $fa-var-bullhorn: "\f0a1"; 117 | $fa-var-bullseye: "\f140"; 118 | $fa-var-bus: "\f207"; 119 | $fa-var-buysellads: "\f20d"; 120 | $fa-var-cab: "\f1ba"; 121 | $fa-var-calculator: "\f1ec"; 122 | $fa-var-calendar: "\f073"; 123 | $fa-var-calendar-check-o: "\f274"; 124 | $fa-var-calendar-minus-o: "\f272"; 125 | $fa-var-calendar-o: "\f133"; 126 | $fa-var-calendar-plus-o: "\f271"; 127 | $fa-var-calendar-times-o: "\f273"; 128 | $fa-var-camera: "\f030"; 129 | $fa-var-camera-retro: "\f083"; 130 | $fa-var-car: "\f1b9"; 131 | $fa-var-caret-down: "\f0d7"; 132 | $fa-var-caret-left: "\f0d9"; 133 | $fa-var-caret-right: "\f0da"; 134 | $fa-var-caret-square-o-down: "\f150"; 135 | $fa-var-caret-square-o-left: "\f191"; 136 | $fa-var-caret-square-o-right: "\f152"; 137 | $fa-var-caret-square-o-up: "\f151"; 138 | $fa-var-caret-up: "\f0d8"; 139 | $fa-var-cart-arrow-down: "\f218"; 140 | $fa-var-cart-plus: "\f217"; 141 | $fa-var-cc: "\f20a"; 142 | $fa-var-cc-amex: "\f1f3"; 143 | $fa-var-cc-diners-club: "\f24c"; 144 | $fa-var-cc-discover: "\f1f2"; 145 | $fa-var-cc-jcb: "\f24b"; 146 | $fa-var-cc-mastercard: "\f1f1"; 147 | $fa-var-cc-paypal: "\f1f4"; 148 | $fa-var-cc-stripe: "\f1f5"; 149 | $fa-var-cc-visa: "\f1f0"; 150 | $fa-var-certificate: "\f0a3"; 151 | $fa-var-chain: "\f0c1"; 152 | $fa-var-chain-broken: "\f127"; 153 | $fa-var-check: "\f00c"; 154 | $fa-var-check-circle: "\f058"; 155 | $fa-var-check-circle-o: "\f05d"; 156 | $fa-var-check-square: "\f14a"; 157 | $fa-var-check-square-o: "\f046"; 158 | $fa-var-chevron-circle-down: "\f13a"; 159 | $fa-var-chevron-circle-left: "\f137"; 160 | $fa-var-chevron-circle-right: "\f138"; 161 | $fa-var-chevron-circle-up: "\f139"; 162 | $fa-var-chevron-down: "\f078"; 163 | $fa-var-chevron-left: "\f053"; 164 | $fa-var-chevron-right: "\f054"; 165 | $fa-var-chevron-up: "\f077"; 166 | $fa-var-child: "\f1ae"; 167 | $fa-var-chrome: "\f268"; 168 | $fa-var-circle: "\f111"; 169 | $fa-var-circle-o: "\f10c"; 170 | $fa-var-circle-o-notch: "\f1ce"; 171 | $fa-var-circle-thin: "\f1db"; 172 | $fa-var-clipboard: "\f0ea"; 173 | $fa-var-clock-o: "\f017"; 174 | $fa-var-clone: "\f24d"; 175 | $fa-var-close: "\f00d"; 176 | $fa-var-cloud: "\f0c2"; 177 | $fa-var-cloud-download: "\f0ed"; 178 | $fa-var-cloud-upload: "\f0ee"; 179 | $fa-var-cny: "\f157"; 180 | $fa-var-code: "\f121"; 181 | $fa-var-code-fork: "\f126"; 182 | $fa-var-codepen: "\f1cb"; 183 | $fa-var-codiepie: "\f284"; 184 | $fa-var-coffee: "\f0f4"; 185 | $fa-var-cog: "\f013"; 186 | $fa-var-cogs: "\f085"; 187 | $fa-var-columns: "\f0db"; 188 | $fa-var-comment: "\f075"; 189 | $fa-var-comment-o: "\f0e5"; 190 | $fa-var-commenting: "\f27a"; 191 | $fa-var-commenting-o: "\f27b"; 192 | $fa-var-comments: "\f086"; 193 | $fa-var-comments-o: "\f0e6"; 194 | $fa-var-compass: "\f14e"; 195 | $fa-var-compress: "\f066"; 196 | $fa-var-connectdevelop: "\f20e"; 197 | $fa-var-contao: "\f26d"; 198 | $fa-var-copy: "\f0c5"; 199 | $fa-var-copyright: "\f1f9"; 200 | $fa-var-creative-commons: "\f25e"; 201 | $fa-var-credit-card: "\f09d"; 202 | $fa-var-credit-card-alt: "\f283"; 203 | $fa-var-crop: "\f125"; 204 | $fa-var-crosshairs: "\f05b"; 205 | $fa-var-css3: "\f13c"; 206 | $fa-var-cube: "\f1b2"; 207 | $fa-var-cubes: "\f1b3"; 208 | $fa-var-cut: "\f0c4"; 209 | $fa-var-cutlery: "\f0f5"; 210 | $fa-var-dashboard: "\f0e4"; 211 | $fa-var-dashcube: "\f210"; 212 | $fa-var-database: "\f1c0"; 213 | $fa-var-deaf: "\f2a4"; 214 | $fa-var-deafness: "\f2a4"; 215 | $fa-var-dedent: "\f03b"; 216 | $fa-var-delicious: "\f1a5"; 217 | $fa-var-desktop: "\f108"; 218 | $fa-var-deviantart: "\f1bd"; 219 | $fa-var-diamond: "\f219"; 220 | $fa-var-digg: "\f1a6"; 221 | $fa-var-dollar: "\f155"; 222 | $fa-var-dot-circle-o: "\f192"; 223 | $fa-var-download: "\f019"; 224 | $fa-var-dribbble: "\f17d"; 225 | $fa-var-drivers-license: "\f2c2"; 226 | $fa-var-drivers-license-o: "\f2c3"; 227 | $fa-var-dropbox: "\f16b"; 228 | $fa-var-drupal: "\f1a9"; 229 | $fa-var-edge: "\f282"; 230 | $fa-var-edit: "\f044"; 231 | $fa-var-eercast: "\f2da"; 232 | $fa-var-eject: "\f052"; 233 | $fa-var-ellipsis-h: "\f141"; 234 | $fa-var-ellipsis-v: "\f142"; 235 | $fa-var-empire: "\f1d1"; 236 | $fa-var-envelope: "\f0e0"; 237 | $fa-var-envelope-o: "\f003"; 238 | $fa-var-envelope-open: "\f2b6"; 239 | $fa-var-envelope-open-o: "\f2b7"; 240 | $fa-var-envelope-square: "\f199"; 241 | $fa-var-envira: "\f299"; 242 | $fa-var-eraser: "\f12d"; 243 | $fa-var-etsy: "\f2d7"; 244 | $fa-var-eur: "\f153"; 245 | $fa-var-euro: "\f153"; 246 | $fa-var-exchange: "\f0ec"; 247 | $fa-var-exclamation: "\f12a"; 248 | $fa-var-exclamation-circle: "\f06a"; 249 | $fa-var-exclamation-triangle: "\f071"; 250 | $fa-var-expand: "\f065"; 251 | $fa-var-expeditedssl: "\f23e"; 252 | $fa-var-external-link: "\f08e"; 253 | $fa-var-external-link-square: "\f14c"; 254 | $fa-var-eye: "\f06e"; 255 | $fa-var-eye-slash: "\f070"; 256 | $fa-var-eyedropper: "\f1fb"; 257 | $fa-var-fa: "\f2b4"; 258 | $fa-var-facebook: "\f09a"; 259 | $fa-var-facebook-f: "\f09a"; 260 | $fa-var-facebook-official: "\f230"; 261 | $fa-var-facebook-square: "\f082"; 262 | $fa-var-fast-backward: "\f049"; 263 | $fa-var-fast-forward: "\f050"; 264 | $fa-var-fax: "\f1ac"; 265 | $fa-var-feed: "\f09e"; 266 | $fa-var-female: "\f182"; 267 | $fa-var-fighter-jet: "\f0fb"; 268 | $fa-var-file: "\f15b"; 269 | $fa-var-file-archive-o: "\f1c6"; 270 | $fa-var-file-audio-o: "\f1c7"; 271 | $fa-var-file-code-o: "\f1c9"; 272 | $fa-var-file-excel-o: "\f1c3"; 273 | $fa-var-file-image-o: "\f1c5"; 274 | $fa-var-file-movie-o: "\f1c8"; 275 | $fa-var-file-o: "\f016"; 276 | $fa-var-file-pdf-o: "\f1c1"; 277 | $fa-var-file-photo-o: "\f1c5"; 278 | $fa-var-file-picture-o: "\f1c5"; 279 | $fa-var-file-powerpoint-o: "\f1c4"; 280 | $fa-var-file-sound-o: "\f1c7"; 281 | $fa-var-file-text: "\f15c"; 282 | $fa-var-file-text-o: "\f0f6"; 283 | $fa-var-file-video-o: "\f1c8"; 284 | $fa-var-file-word-o: "\f1c2"; 285 | $fa-var-file-zip-o: "\f1c6"; 286 | $fa-var-files-o: "\f0c5"; 287 | $fa-var-film: "\f008"; 288 | $fa-var-filter: "\f0b0"; 289 | $fa-var-fire: "\f06d"; 290 | $fa-var-fire-extinguisher: "\f134"; 291 | $fa-var-firefox: "\f269"; 292 | $fa-var-first-order: "\f2b0"; 293 | $fa-var-flag: "\f024"; 294 | $fa-var-flag-checkered: "\f11e"; 295 | $fa-var-flag-o: "\f11d"; 296 | $fa-var-flash: "\f0e7"; 297 | $fa-var-flask: "\f0c3"; 298 | $fa-var-flickr: "\f16e"; 299 | $fa-var-floppy-o: "\f0c7"; 300 | $fa-var-folder: "\f07b"; 301 | $fa-var-folder-o: "\f114"; 302 | $fa-var-folder-open: "\f07c"; 303 | $fa-var-folder-open-o: "\f115"; 304 | $fa-var-font: "\f031"; 305 | $fa-var-font-awesome: "\f2b4"; 306 | $fa-var-fonticons: "\f280"; 307 | $fa-var-fort-awesome: "\f286"; 308 | $fa-var-forumbee: "\f211"; 309 | $fa-var-forward: "\f04e"; 310 | $fa-var-foursquare: "\f180"; 311 | $fa-var-free-code-camp: "\f2c5"; 312 | $fa-var-frown-o: "\f119"; 313 | $fa-var-futbol-o: "\f1e3"; 314 | $fa-var-gamepad: "\f11b"; 315 | $fa-var-gavel: "\f0e3"; 316 | $fa-var-gbp: "\f154"; 317 | $fa-var-ge: "\f1d1"; 318 | $fa-var-gear: "\f013"; 319 | $fa-var-gears: "\f085"; 320 | $fa-var-genderless: "\f22d"; 321 | $fa-var-get-pocket: "\f265"; 322 | $fa-var-gg: "\f260"; 323 | $fa-var-gg-circle: "\f261"; 324 | $fa-var-gift: "\f06b"; 325 | $fa-var-git: "\f1d3"; 326 | $fa-var-git-square: "\f1d2"; 327 | $fa-var-github: "\f09b"; 328 | $fa-var-github-alt: "\f113"; 329 | $fa-var-github-square: "\f092"; 330 | $fa-var-gitlab: "\f296"; 331 | $fa-var-gittip: "\f184"; 332 | $fa-var-glass: "\f000"; 333 | $fa-var-glide: "\f2a5"; 334 | $fa-var-glide-g: "\f2a6"; 335 | $fa-var-globe: "\f0ac"; 336 | $fa-var-google: "\f1a0"; 337 | $fa-var-google-plus: "\f0d5"; 338 | $fa-var-google-plus-circle: "\f2b3"; 339 | $fa-var-google-plus-official: "\f2b3"; 340 | $fa-var-google-plus-square: "\f0d4"; 341 | $fa-var-google-wallet: "\f1ee"; 342 | $fa-var-graduation-cap: "\f19d"; 343 | $fa-var-gratipay: "\f184"; 344 | $fa-var-grav: "\f2d6"; 345 | $fa-var-group: "\f0c0"; 346 | $fa-var-h-square: "\f0fd"; 347 | $fa-var-hacker-news: "\f1d4"; 348 | $fa-var-hand-grab-o: "\f255"; 349 | $fa-var-hand-lizard-o: "\f258"; 350 | $fa-var-hand-o-down: "\f0a7"; 351 | $fa-var-hand-o-left: "\f0a5"; 352 | $fa-var-hand-o-right: "\f0a4"; 353 | $fa-var-hand-o-up: "\f0a6"; 354 | $fa-var-hand-paper-o: "\f256"; 355 | $fa-var-hand-peace-o: "\f25b"; 356 | $fa-var-hand-pointer-o: "\f25a"; 357 | $fa-var-hand-rock-o: "\f255"; 358 | $fa-var-hand-scissors-o: "\f257"; 359 | $fa-var-hand-spock-o: "\f259"; 360 | $fa-var-hand-stop-o: "\f256"; 361 | $fa-var-handshake-o: "\f2b5"; 362 | $fa-var-hard-of-hearing: "\f2a4"; 363 | $fa-var-hashtag: "\f292"; 364 | $fa-var-hdd-o: "\f0a0"; 365 | $fa-var-header: "\f1dc"; 366 | $fa-var-headphones: "\f025"; 367 | $fa-var-heart: "\f004"; 368 | $fa-var-heart-o: "\f08a"; 369 | $fa-var-heartbeat: "\f21e"; 370 | $fa-var-history: "\f1da"; 371 | $fa-var-home: "\f015"; 372 | $fa-var-hospital-o: "\f0f8"; 373 | $fa-var-hotel: "\f236"; 374 | $fa-var-hourglass: "\f254"; 375 | $fa-var-hourglass-1: "\f251"; 376 | $fa-var-hourglass-2: "\f252"; 377 | $fa-var-hourglass-3: "\f253"; 378 | $fa-var-hourglass-end: "\f253"; 379 | $fa-var-hourglass-half: "\f252"; 380 | $fa-var-hourglass-o: "\f250"; 381 | $fa-var-hourglass-start: "\f251"; 382 | $fa-var-houzz: "\f27c"; 383 | $fa-var-html5: "\f13b"; 384 | $fa-var-i-cursor: "\f246"; 385 | $fa-var-id-badge: "\f2c1"; 386 | $fa-var-id-card: "\f2c2"; 387 | $fa-var-id-card-o: "\f2c3"; 388 | $fa-var-ils: "\f20b"; 389 | $fa-var-image: "\f03e"; 390 | $fa-var-imdb: "\f2d8"; 391 | $fa-var-inbox: "\f01c"; 392 | $fa-var-indent: "\f03c"; 393 | $fa-var-industry: "\f275"; 394 | $fa-var-info: "\f129"; 395 | $fa-var-info-circle: "\f05a"; 396 | $fa-var-inr: "\f156"; 397 | $fa-var-instagram: "\f16d"; 398 | $fa-var-institution: "\f19c"; 399 | $fa-var-internet-explorer: "\f26b"; 400 | $fa-var-intersex: "\f224"; 401 | $fa-var-ioxhost: "\f208"; 402 | $fa-var-italic: "\f033"; 403 | $fa-var-joomla: "\f1aa"; 404 | $fa-var-jpy: "\f157"; 405 | $fa-var-jsfiddle: "\f1cc"; 406 | $fa-var-key: "\f084"; 407 | $fa-var-keyboard-o: "\f11c"; 408 | $fa-var-krw: "\f159"; 409 | $fa-var-language: "\f1ab"; 410 | $fa-var-laptop: "\f109"; 411 | $fa-var-lastfm: "\f202"; 412 | $fa-var-lastfm-square: "\f203"; 413 | $fa-var-leaf: "\f06c"; 414 | $fa-var-leanpub: "\f212"; 415 | $fa-var-legal: "\f0e3"; 416 | $fa-var-lemon-o: "\f094"; 417 | $fa-var-level-down: "\f149"; 418 | $fa-var-level-up: "\f148"; 419 | $fa-var-life-bouy: "\f1cd"; 420 | $fa-var-life-buoy: "\f1cd"; 421 | $fa-var-life-ring: "\f1cd"; 422 | $fa-var-life-saver: "\f1cd"; 423 | $fa-var-lightbulb-o: "\f0eb"; 424 | $fa-var-line-chart: "\f201"; 425 | $fa-var-link: "\f0c1"; 426 | $fa-var-linkedin: "\f0e1"; 427 | $fa-var-linkedin-square: "\f08c"; 428 | $fa-var-linode: "\f2b8"; 429 | $fa-var-linux: "\f17c"; 430 | $fa-var-list: "\f03a"; 431 | $fa-var-list-alt: "\f022"; 432 | $fa-var-list-ol: "\f0cb"; 433 | $fa-var-list-ul: "\f0ca"; 434 | $fa-var-location-arrow: "\f124"; 435 | $fa-var-lock: "\f023"; 436 | $fa-var-long-arrow-down: "\f175"; 437 | $fa-var-long-arrow-left: "\f177"; 438 | $fa-var-long-arrow-right: "\f178"; 439 | $fa-var-long-arrow-up: "\f176"; 440 | $fa-var-low-vision: "\f2a8"; 441 | $fa-var-magic: "\f0d0"; 442 | $fa-var-magnet: "\f076"; 443 | $fa-var-mail-forward: "\f064"; 444 | $fa-var-mail-reply: "\f112"; 445 | $fa-var-mail-reply-all: "\f122"; 446 | $fa-var-male: "\f183"; 447 | $fa-var-map: "\f279"; 448 | $fa-var-map-marker: "\f041"; 449 | $fa-var-map-o: "\f278"; 450 | $fa-var-map-pin: "\f276"; 451 | $fa-var-map-signs: "\f277"; 452 | $fa-var-mars: "\f222"; 453 | $fa-var-mars-double: "\f227"; 454 | $fa-var-mars-stroke: "\f229"; 455 | $fa-var-mars-stroke-h: "\f22b"; 456 | $fa-var-mars-stroke-v: "\f22a"; 457 | $fa-var-maxcdn: "\f136"; 458 | $fa-var-meanpath: "\f20c"; 459 | $fa-var-medium: "\f23a"; 460 | $fa-var-medkit: "\f0fa"; 461 | $fa-var-meetup: "\f2e0"; 462 | $fa-var-meh-o: "\f11a"; 463 | $fa-var-mercury: "\f223"; 464 | $fa-var-microchip: "\f2db"; 465 | $fa-var-microphone: "\f130"; 466 | $fa-var-microphone-slash: "\f131"; 467 | $fa-var-minus: "\f068"; 468 | $fa-var-minus-circle: "\f056"; 469 | $fa-var-minus-square: "\f146"; 470 | $fa-var-minus-square-o: "\f147"; 471 | $fa-var-mixcloud: "\f289"; 472 | $fa-var-mobile: "\f10b"; 473 | $fa-var-mobile-phone: "\f10b"; 474 | $fa-var-modx: "\f285"; 475 | $fa-var-money: "\f0d6"; 476 | $fa-var-moon-o: "\f186"; 477 | $fa-var-mortar-board: "\f19d"; 478 | $fa-var-motorcycle: "\f21c"; 479 | $fa-var-mouse-pointer: "\f245"; 480 | $fa-var-music: "\f001"; 481 | $fa-var-navicon: "\f0c9"; 482 | $fa-var-neuter: "\f22c"; 483 | $fa-var-newspaper-o: "\f1ea"; 484 | $fa-var-object-group: "\f247"; 485 | $fa-var-object-ungroup: "\f248"; 486 | $fa-var-odnoklassniki: "\f263"; 487 | $fa-var-odnoklassniki-square: "\f264"; 488 | $fa-var-opencart: "\f23d"; 489 | $fa-var-openid: "\f19b"; 490 | $fa-var-opera: "\f26a"; 491 | $fa-var-optin-monster: "\f23c"; 492 | $fa-var-outdent: "\f03b"; 493 | $fa-var-pagelines: "\f18c"; 494 | $fa-var-paint-brush: "\f1fc"; 495 | $fa-var-paper-plane: "\f1d8"; 496 | $fa-var-paper-plane-o: "\f1d9"; 497 | $fa-var-paperclip: "\f0c6"; 498 | $fa-var-paragraph: "\f1dd"; 499 | $fa-var-paste: "\f0ea"; 500 | $fa-var-pause: "\f04c"; 501 | $fa-var-pause-circle: "\f28b"; 502 | $fa-var-pause-circle-o: "\f28c"; 503 | $fa-var-paw: "\f1b0"; 504 | $fa-var-paypal: "\f1ed"; 505 | $fa-var-pencil: "\f040"; 506 | $fa-var-pencil-square: "\f14b"; 507 | $fa-var-pencil-square-o: "\f044"; 508 | $fa-var-percent: "\f295"; 509 | $fa-var-phone: "\f095"; 510 | $fa-var-phone-square: "\f098"; 511 | $fa-var-photo: "\f03e"; 512 | $fa-var-picture-o: "\f03e"; 513 | $fa-var-pie-chart: "\f200"; 514 | $fa-var-pied-piper: "\f2ae"; 515 | $fa-var-pied-piper-alt: "\f1a8"; 516 | $fa-var-pied-piper-pp: "\f1a7"; 517 | $fa-var-pinterest: "\f0d2"; 518 | $fa-var-pinterest-p: "\f231"; 519 | $fa-var-pinterest-square: "\f0d3"; 520 | $fa-var-plane: "\f072"; 521 | $fa-var-play: "\f04b"; 522 | $fa-var-play-circle: "\f144"; 523 | $fa-var-play-circle-o: "\f01d"; 524 | $fa-var-plug: "\f1e6"; 525 | $fa-var-plus: "\f067"; 526 | $fa-var-plus-circle: "\f055"; 527 | $fa-var-plus-square: "\f0fe"; 528 | $fa-var-plus-square-o: "\f196"; 529 | $fa-var-podcast: "\f2ce"; 530 | $fa-var-power-off: "\f011"; 531 | $fa-var-print: "\f02f"; 532 | $fa-var-product-hunt: "\f288"; 533 | $fa-var-puzzle-piece: "\f12e"; 534 | $fa-var-qq: "\f1d6"; 535 | $fa-var-qrcode: "\f029"; 536 | $fa-var-question: "\f128"; 537 | $fa-var-question-circle: "\f059"; 538 | $fa-var-question-circle-o: "\f29c"; 539 | $fa-var-quora: "\f2c4"; 540 | $fa-var-quote-left: "\f10d"; 541 | $fa-var-quote-right: "\f10e"; 542 | $fa-var-ra: "\f1d0"; 543 | $fa-var-random: "\f074"; 544 | $fa-var-ravelry: "\f2d9"; 545 | $fa-var-rebel: "\f1d0"; 546 | $fa-var-recycle: "\f1b8"; 547 | $fa-var-reddit: "\f1a1"; 548 | $fa-var-reddit-alien: "\f281"; 549 | $fa-var-reddit-square: "\f1a2"; 550 | $fa-var-refresh: "\f021"; 551 | $fa-var-registered: "\f25d"; 552 | $fa-var-remove: "\f00d"; 553 | $fa-var-renren: "\f18b"; 554 | $fa-var-reorder: "\f0c9"; 555 | $fa-var-repeat: "\f01e"; 556 | $fa-var-reply: "\f112"; 557 | $fa-var-reply-all: "\f122"; 558 | $fa-var-resistance: "\f1d0"; 559 | $fa-var-retweet: "\f079"; 560 | $fa-var-rmb: "\f157"; 561 | $fa-var-road: "\f018"; 562 | $fa-var-rocket: "\f135"; 563 | $fa-var-rotate-left: "\f0e2"; 564 | $fa-var-rotate-right: "\f01e"; 565 | $fa-var-rouble: "\f158"; 566 | $fa-var-rss: "\f09e"; 567 | $fa-var-rss-square: "\f143"; 568 | $fa-var-rub: "\f158"; 569 | $fa-var-ruble: "\f158"; 570 | $fa-var-rupee: "\f156"; 571 | $fa-var-s15: "\f2cd"; 572 | $fa-var-safari: "\f267"; 573 | $fa-var-save: "\f0c7"; 574 | $fa-var-scissors: "\f0c4"; 575 | $fa-var-scribd: "\f28a"; 576 | $fa-var-search: "\f002"; 577 | $fa-var-search-minus: "\f010"; 578 | $fa-var-search-plus: "\f00e"; 579 | $fa-var-sellsy: "\f213"; 580 | $fa-var-send: "\f1d8"; 581 | $fa-var-send-o: "\f1d9"; 582 | $fa-var-server: "\f233"; 583 | $fa-var-share: "\f064"; 584 | $fa-var-share-alt: "\f1e0"; 585 | $fa-var-share-alt-square: "\f1e1"; 586 | $fa-var-share-square: "\f14d"; 587 | $fa-var-share-square-o: "\f045"; 588 | $fa-var-shekel: "\f20b"; 589 | $fa-var-sheqel: "\f20b"; 590 | $fa-var-shield: "\f132"; 591 | $fa-var-ship: "\f21a"; 592 | $fa-var-shirtsinbulk: "\f214"; 593 | $fa-var-shopping-bag: "\f290"; 594 | $fa-var-shopping-basket: "\f291"; 595 | $fa-var-shopping-cart: "\f07a"; 596 | $fa-var-shower: "\f2cc"; 597 | $fa-var-sign-in: "\f090"; 598 | $fa-var-sign-language: "\f2a7"; 599 | $fa-var-sign-out: "\f08b"; 600 | $fa-var-signal: "\f012"; 601 | $fa-var-signing: "\f2a7"; 602 | $fa-var-simplybuilt: "\f215"; 603 | $fa-var-sitemap: "\f0e8"; 604 | $fa-var-skyatlas: "\f216"; 605 | $fa-var-skype: "\f17e"; 606 | $fa-var-slack: "\f198"; 607 | $fa-var-sliders: "\f1de"; 608 | $fa-var-slideshare: "\f1e7"; 609 | $fa-var-smile-o: "\f118"; 610 | $fa-var-snapchat: "\f2ab"; 611 | $fa-var-snapchat-ghost: "\f2ac"; 612 | $fa-var-snapchat-square: "\f2ad"; 613 | $fa-var-snowflake-o: "\f2dc"; 614 | $fa-var-soccer-ball-o: "\f1e3"; 615 | $fa-var-sort: "\f0dc"; 616 | $fa-var-sort-alpha-asc: "\f15d"; 617 | $fa-var-sort-alpha-desc: "\f15e"; 618 | $fa-var-sort-amount-asc: "\f160"; 619 | $fa-var-sort-amount-desc: "\f161"; 620 | $fa-var-sort-asc: "\f0de"; 621 | $fa-var-sort-desc: "\f0dd"; 622 | $fa-var-sort-down: "\f0dd"; 623 | $fa-var-sort-numeric-asc: "\f162"; 624 | $fa-var-sort-numeric-desc: "\f163"; 625 | $fa-var-sort-up: "\f0de"; 626 | $fa-var-soundcloud: "\f1be"; 627 | $fa-var-space-shuttle: "\f197"; 628 | $fa-var-spinner: "\f110"; 629 | $fa-var-spoon: "\f1b1"; 630 | $fa-var-spotify: "\f1bc"; 631 | $fa-var-square: "\f0c8"; 632 | $fa-var-square-o: "\f096"; 633 | $fa-var-stack-exchange: "\f18d"; 634 | $fa-var-stack-overflow: "\f16c"; 635 | $fa-var-star: "\f005"; 636 | $fa-var-star-half: "\f089"; 637 | $fa-var-star-half-empty: "\f123"; 638 | $fa-var-star-half-full: "\f123"; 639 | $fa-var-star-half-o: "\f123"; 640 | $fa-var-star-o: "\f006"; 641 | $fa-var-steam: "\f1b6"; 642 | $fa-var-steam-square: "\f1b7"; 643 | $fa-var-step-backward: "\f048"; 644 | $fa-var-step-forward: "\f051"; 645 | $fa-var-stethoscope: "\f0f1"; 646 | $fa-var-sticky-note: "\f249"; 647 | $fa-var-sticky-note-o: "\f24a"; 648 | $fa-var-stop: "\f04d"; 649 | $fa-var-stop-circle: "\f28d"; 650 | $fa-var-stop-circle-o: "\f28e"; 651 | $fa-var-street-view: "\f21d"; 652 | $fa-var-strikethrough: "\f0cc"; 653 | $fa-var-stumbleupon: "\f1a4"; 654 | $fa-var-stumbleupon-circle: "\f1a3"; 655 | $fa-var-subscript: "\f12c"; 656 | $fa-var-subway: "\f239"; 657 | $fa-var-suitcase: "\f0f2"; 658 | $fa-var-sun-o: "\f185"; 659 | $fa-var-superpowers: "\f2dd"; 660 | $fa-var-superscript: "\f12b"; 661 | $fa-var-support: "\f1cd"; 662 | $fa-var-table: "\f0ce"; 663 | $fa-var-tablet: "\f10a"; 664 | $fa-var-tachometer: "\f0e4"; 665 | $fa-var-tag: "\f02b"; 666 | $fa-var-tags: "\f02c"; 667 | $fa-var-tasks: "\f0ae"; 668 | $fa-var-taxi: "\f1ba"; 669 | $fa-var-telegram: "\f2c6"; 670 | $fa-var-television: "\f26c"; 671 | $fa-var-tencent-weibo: "\f1d5"; 672 | $fa-var-terminal: "\f120"; 673 | $fa-var-text-height: "\f034"; 674 | $fa-var-text-width: "\f035"; 675 | $fa-var-th: "\f00a"; 676 | $fa-var-th-large: "\f009"; 677 | $fa-var-th-list: "\f00b"; 678 | $fa-var-themeisle: "\f2b2"; 679 | $fa-var-thermometer: "\f2c7"; 680 | $fa-var-thermometer-0: "\f2cb"; 681 | $fa-var-thermometer-1: "\f2ca"; 682 | $fa-var-thermometer-2: "\f2c9"; 683 | $fa-var-thermometer-3: "\f2c8"; 684 | $fa-var-thermometer-4: "\f2c7"; 685 | $fa-var-thermometer-empty: "\f2cb"; 686 | $fa-var-thermometer-full: "\f2c7"; 687 | $fa-var-thermometer-half: "\f2c9"; 688 | $fa-var-thermometer-quarter: "\f2ca"; 689 | $fa-var-thermometer-three-quarters: "\f2c8"; 690 | $fa-var-thumb-tack: "\f08d"; 691 | $fa-var-thumbs-down: "\f165"; 692 | $fa-var-thumbs-o-down: "\f088"; 693 | $fa-var-thumbs-o-up: "\f087"; 694 | $fa-var-thumbs-up: "\f164"; 695 | $fa-var-ticket: "\f145"; 696 | $fa-var-times: "\f00d"; 697 | $fa-var-times-circle: "\f057"; 698 | $fa-var-times-circle-o: "\f05c"; 699 | $fa-var-times-rectangle: "\f2d3"; 700 | $fa-var-times-rectangle-o: "\f2d4"; 701 | $fa-var-tint: "\f043"; 702 | $fa-var-toggle-down: "\f150"; 703 | $fa-var-toggle-left: "\f191"; 704 | $fa-var-toggle-off: "\f204"; 705 | $fa-var-toggle-on: "\f205"; 706 | $fa-var-toggle-right: "\f152"; 707 | $fa-var-toggle-up: "\f151"; 708 | $fa-var-trademark: "\f25c"; 709 | $fa-var-train: "\f238"; 710 | $fa-var-transgender: "\f224"; 711 | $fa-var-transgender-alt: "\f225"; 712 | $fa-var-trash: "\f1f8"; 713 | $fa-var-trash-o: "\f014"; 714 | $fa-var-tree: "\f1bb"; 715 | $fa-var-trello: "\f181"; 716 | $fa-var-tripadvisor: "\f262"; 717 | $fa-var-trophy: "\f091"; 718 | $fa-var-truck: "\f0d1"; 719 | $fa-var-try: "\f195"; 720 | $fa-var-tty: "\f1e4"; 721 | $fa-var-tumblr: "\f173"; 722 | $fa-var-tumblr-square: "\f174"; 723 | $fa-var-turkish-lira: "\f195"; 724 | $fa-var-tv: "\f26c"; 725 | $fa-var-twitch: "\f1e8"; 726 | $fa-var-twitter: "\f099"; 727 | $fa-var-twitter-square: "\f081"; 728 | $fa-var-umbrella: "\f0e9"; 729 | $fa-var-underline: "\f0cd"; 730 | $fa-var-undo: "\f0e2"; 731 | $fa-var-universal-access: "\f29a"; 732 | $fa-var-university: "\f19c"; 733 | $fa-var-unlink: "\f127"; 734 | $fa-var-unlock: "\f09c"; 735 | $fa-var-unlock-alt: "\f13e"; 736 | $fa-var-unsorted: "\f0dc"; 737 | $fa-var-upload: "\f093"; 738 | $fa-var-usb: "\f287"; 739 | $fa-var-usd: "\f155"; 740 | $fa-var-user: "\f007"; 741 | $fa-var-user-circle: "\f2bd"; 742 | $fa-var-user-circle-o: "\f2be"; 743 | $fa-var-user-md: "\f0f0"; 744 | $fa-var-user-o: "\f2c0"; 745 | $fa-var-user-plus: "\f234"; 746 | $fa-var-user-secret: "\f21b"; 747 | $fa-var-user-times: "\f235"; 748 | $fa-var-users: "\f0c0"; 749 | $fa-var-vcard: "\f2bb"; 750 | $fa-var-vcard-o: "\f2bc"; 751 | $fa-var-venus: "\f221"; 752 | $fa-var-venus-double: "\f226"; 753 | $fa-var-venus-mars: "\f228"; 754 | $fa-var-viacoin: "\f237"; 755 | $fa-var-viadeo: "\f2a9"; 756 | $fa-var-viadeo-square: "\f2aa"; 757 | $fa-var-video-camera: "\f03d"; 758 | $fa-var-vimeo: "\f27d"; 759 | $fa-var-vimeo-square: "\f194"; 760 | $fa-var-vine: "\f1ca"; 761 | $fa-var-vk: "\f189"; 762 | $fa-var-volume-control-phone: "\f2a0"; 763 | $fa-var-volume-down: "\f027"; 764 | $fa-var-volume-off: "\f026"; 765 | $fa-var-volume-up: "\f028"; 766 | $fa-var-warning: "\f071"; 767 | $fa-var-wechat: "\f1d7"; 768 | $fa-var-weibo: "\f18a"; 769 | $fa-var-weixin: "\f1d7"; 770 | $fa-var-whatsapp: "\f232"; 771 | $fa-var-wheelchair: "\f193"; 772 | $fa-var-wheelchair-alt: "\f29b"; 773 | $fa-var-wifi: "\f1eb"; 774 | $fa-var-wikipedia-w: "\f266"; 775 | $fa-var-window-close: "\f2d3"; 776 | $fa-var-window-close-o: "\f2d4"; 777 | $fa-var-window-maximize: "\f2d0"; 778 | $fa-var-window-minimize: "\f2d1"; 779 | $fa-var-window-restore: "\f2d2"; 780 | $fa-var-windows: "\f17a"; 781 | $fa-var-won: "\f159"; 782 | $fa-var-wordpress: "\f19a"; 783 | $fa-var-wpbeginner: "\f297"; 784 | $fa-var-wpexplorer: "\f2de"; 785 | $fa-var-wpforms: "\f298"; 786 | $fa-var-wrench: "\f0ad"; 787 | $fa-var-xing: "\f168"; 788 | $fa-var-xing-square: "\f169"; 789 | $fa-var-y-combinator: "\f23b"; 790 | $fa-var-y-combinator-square: "\f1d4"; 791 | $fa-var-yahoo: "\f19e"; 792 | $fa-var-yc: "\f23b"; 793 | $fa-var-yc-square: "\f1d4"; 794 | $fa-var-yelp: "\f1e9"; 795 | $fa-var-yen: "\f157"; 796 | $fa-var-yoast: "\f2b1"; 797 | $fa-var-youtube: "\f167"; 798 | $fa-var-youtube-play: "\f16a"; 799 | $fa-var-youtube-square: "\f166"; 800 | 801 | -------------------------------------------------------------------------------- /src/font-awesome/scss/font-awesome.scss: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome 3 | * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) 4 | */ 5 | 6 | @import "variables"; 7 | @import "mixins"; 8 | @import "path"; 9 | @import "core"; 10 | @import "larger"; 11 | @import "fixed-width"; 12 | @import "list"; 13 | @import "bordered-pulled"; 14 | @import "animated"; 15 | @import "rotated-flipped"; 16 | @import "stacked"; 17 | @import "icons"; 18 | @import "screen-reader"; 19 | -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css?family=Raleway|Source+Code+Pro'); 2 | body { 3 | margin: 0; 4 | padding: 0; 5 | font-family: 'Raleway', sans-serif !important; 6 | color: #444; 7 | margin-bottom: 50px; 8 | background: #fefefe; 9 | } 10 | 11 | h1, h2, h3, h4 { 12 | color: #097b4e; 13 | } 14 | 15 | a { 16 | color: #59b1ef; 17 | } 18 | 19 | #mc_embed_signup input, 20 | input { 21 | font-family: 'Source Code Pro', sans-serif; 22 | transition: box-shadow 0.3s, border 0.3s; 23 | border: 1px solid #59b1ef !important; 24 | box-shadow: 0px 4px 10px #dcdada !important; 25 | top: -2px; 26 | position: relative; 27 | border-radius: 8px !important; 28 | } 29 | 30 | #mc_embed_signup input:focus, 31 | input:focus { 32 | box-shadow: 0px 4px 10px #bbb !important; 33 | border: 1px solid #fefefe !important; 34 | } 35 | 36 | #mc_embed_signup .btn, 37 | .btn { 38 | font-family: 'Source Code Pro', sans-serif; 39 | transition: box-shadow 0.3s, border 0.3s, background 0s; 40 | box-shadow: 0px 4px 10px #dcdada; 41 | font-weight: 300; 42 | font-size: 1.2rem; 43 | border: 1px solid #fff !important; 44 | border-radius: 8px; 45 | color: #fff; 46 | background: #59b1ef; 47 | } 48 | 49 | .btn.clean { 50 | background: #fff; 51 | color: #444; 52 | } 53 | .btn.clean:hover { 54 | color: #444; 55 | } 56 | 57 | .btn.clean:active { 58 | color: #444; 59 | } 60 | 61 | .btn.clean:focus { 62 | color: #444; 63 | } 64 | 65 | .btn.full-width { 66 | width: 100%; 67 | } 68 | 69 | .btn.disabled-btn { 70 | cursor: not-allowed; 71 | background-color: #eee; 72 | color: #888; 73 | } 74 | 75 | input.full-width { 76 | width: 100%; 77 | } 78 | 79 | #mc_embed_signup .btn:hover, #mc_embed_signup .btn:active, #mc_embed_signup .btn:focus, 80 | .btn:hover, .btn:active, .btn:focus { 81 | color: #fff; 82 | box-shadow: 0px 4px 10px #bbb !important; 83 | border: 1px solid #fff !important; 84 | } 85 | 86 | .modal { 87 | position: fixed; 88 | transform: translate(-50%, -50%); 89 | top: 25%; 90 | left: 50%; 91 | box-shadow: 0px 0px 15px #ddd; 92 | border: 1px solid #bbb; 93 | background : #fff; 94 | overflow: auto; 95 | border-radius: 4px; 96 | outline: none; 97 | padding: 20px; 98 | width: 300px; 99 | } 100 | .modal.add-tokens { 101 | top: 45%; 102 | width: 350px; 103 | } 104 | 105 | .modal .modal-notice { 106 | margin: 10px 0px 0px 0px; 107 | font-size: 1.3rem; 108 | color: #666; 109 | } 110 | .tooltip { 111 | display: none; 112 | position: absolute; 113 | bottom: 55px; 114 | left: 0px; 115 | width: 100%; 116 | border-radius: 5px; 117 | background-color: #444; 118 | color: #fff; 119 | padding: 10px; 120 | box-sizing: border-box; 121 | } 122 | .tooltip-button { 123 | position: relative; 124 | display: block; 125 | } 126 | .visible { 127 | display: block; 128 | } 129 | 130 | .well { 131 | border: 1px solid #ddd; 132 | margin-bottom: 10px; 133 | padding: 10px; 134 | border-radius: 5px; 135 | } 136 | .right { 137 | float: right; 138 | } 139 | code { 140 | padding: 8px; 141 | } 142 | 143 | /* Skeleton.css Overrides */ 144 | ul { 145 | list-style: circle !important; 146 | margin-bottom: 1.5rem !important; 147 | } 148 | 149 | ol { 150 | list-style: decimal !important; 151 | margin-bottom: 1.5rem !important; 152 | } 153 | 154 | li { 155 | margin-left: 1.7rem !important; 156 | 157 | } -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import App from './App'; 5 | 6 | ReactDOM.render(, document.getElementById('root')); 7 | -------------------------------------------------------------------------------- /src/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/normalize.css: -------------------------------------------------------------------------------- 1 | /*! normalize.css v3.0.2 | MIT License | git.io/normalize */ 2 | 3 | /** 4 | * 1. Set default font family to sans-serif. 5 | * 2. Prevent iOS text size adjust after orientation change, without disabling 6 | * user zoom. 7 | */ 8 | 9 | html { 10 | font-family: sans-serif; /* 1 */ 11 | -ms-text-size-adjust: 100%; /* 2 */ 12 | -webkit-text-size-adjust: 100%; /* 2 */ 13 | } 14 | 15 | /** 16 | * Remove default margin. 17 | */ 18 | 19 | body { 20 | margin: 0; 21 | } 22 | 23 | /* HTML5 display definitions 24 | ========================================================================== */ 25 | 26 | /** 27 | * Correct `block` display not defined for any HTML5 element in IE 8/9. 28 | * Correct `block` display not defined for `details` or `summary` in IE 10/11 29 | * and Firefox. 30 | * Correct `block` display not defined for `main` in IE 11. 31 | */ 32 | 33 | article, 34 | aside, 35 | details, 36 | figcaption, 37 | figure, 38 | footer, 39 | header, 40 | hgroup, 41 | main, 42 | menu, 43 | nav, 44 | section, 45 | summary { 46 | display: block; 47 | } 48 | 49 | /** 50 | * 1. Correct `inline-block` display not defined in IE 8/9. 51 | * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera. 52 | */ 53 | 54 | audio, 55 | canvas, 56 | progress, 57 | video { 58 | display: inline-block; /* 1 */ 59 | vertical-align: baseline; /* 2 */ 60 | } 61 | 62 | /** 63 | * Prevent modern browsers from displaying `audio` without controls. 64 | * Remove excess height in iOS 5 devices. 65 | */ 66 | 67 | audio:not([controls]) { 68 | display: none; 69 | height: 0; 70 | } 71 | 72 | /** 73 | * Address `[hidden]` styling not present in IE 8/9/10. 74 | * Hide the `template` element in IE 8/9/11, Safari, and Firefox < 22. 75 | */ 76 | 77 | [hidden], 78 | template { 79 | display: none; 80 | } 81 | 82 | /* Links 83 | ========================================================================== */ 84 | 85 | /** 86 | * Remove the gray background color from active links in IE 10. 87 | */ 88 | 89 | a { 90 | background-color: transparent; 91 | } 92 | 93 | /** 94 | * Improve readability when focused and also mouse hovered in all browsers. 95 | */ 96 | 97 | a:active, 98 | a:hover { 99 | outline: 0; 100 | } 101 | 102 | /* Text-level semantics 103 | ========================================================================== */ 104 | 105 | /** 106 | * Address styling not present in IE 8/9/10/11, Safari, and Chrome. 107 | */ 108 | 109 | abbr[title] { 110 | border-bottom: 1px dotted; 111 | } 112 | 113 | /** 114 | * Address style set to `bolder` in Firefox 4+, Safari, and Chrome. 115 | */ 116 | 117 | b, 118 | strong { 119 | font-weight: bold; 120 | } 121 | 122 | /** 123 | * Address styling not present in Safari and Chrome. 124 | */ 125 | 126 | dfn { 127 | font-style: italic; 128 | } 129 | 130 | /** 131 | * Address variable `h1` font-size and margin within `section` and `article` 132 | * contexts in Firefox 4+, Safari, and Chrome. 133 | */ 134 | 135 | h1 { 136 | font-size: 2em; 137 | margin: 0.67em 0; 138 | } 139 | 140 | /** 141 | * Address styling not present in IE 8/9. 142 | */ 143 | 144 | mark { 145 | background: #ff0; 146 | color: #000; 147 | } 148 | 149 | /** 150 | * Address inconsistent and variable font size in all browsers. 151 | */ 152 | 153 | small { 154 | font-size: 80%; 155 | } 156 | 157 | /** 158 | * Prevent `sub` and `sup` affecting `line-height` in all browsers. 159 | */ 160 | 161 | sub, 162 | sup { 163 | font-size: 75%; 164 | line-height: 0; 165 | position: relative; 166 | vertical-align: baseline; 167 | } 168 | 169 | sup { 170 | top: -0.5em; 171 | } 172 | 173 | sub { 174 | bottom: -0.25em; 175 | } 176 | 177 | /* Embedded content 178 | ========================================================================== */ 179 | 180 | /** 181 | * Remove border when inside `a` element in IE 8/9/10. 182 | */ 183 | 184 | img { 185 | border: 0; 186 | } 187 | 188 | /** 189 | * Correct overflow not hidden in IE 9/10/11. 190 | */ 191 | 192 | svg:not(:root) { 193 | overflow: hidden; 194 | } 195 | 196 | /* Grouping content 197 | ========================================================================== */ 198 | 199 | /** 200 | * Address margin not present in IE 8/9 and Safari. 201 | */ 202 | 203 | figure { 204 | margin: 1em 40px; 205 | } 206 | 207 | /** 208 | * Address differences between Firefox and other browsers. 209 | */ 210 | 211 | hr { 212 | -moz-box-sizing: content-box; 213 | box-sizing: content-box; 214 | height: 0; 215 | } 216 | 217 | /** 218 | * Contain overflow in all browsers. 219 | */ 220 | 221 | pre { 222 | overflow: auto; 223 | } 224 | 225 | /** 226 | * Address odd `em`-unit font size rendering in all browsers. 227 | */ 228 | 229 | code, 230 | kbd, 231 | pre, 232 | samp { 233 | font-family: monospace, monospace; 234 | font-size: 1em; 235 | } 236 | 237 | /* Forms 238 | ========================================================================== */ 239 | 240 | /** 241 | * Known limitation: by default, Chrome and Safari on OS X allow very limited 242 | * styling of `select`, unless a `border` property is set. 243 | */ 244 | 245 | /** 246 | * 1. Correct color not being inherited. 247 | * Known issue: affects color of disabled elements. 248 | * 2. Correct font properties not being inherited. 249 | * 3. Address margins set differently in Firefox 4+, Safari, and Chrome. 250 | */ 251 | 252 | button, 253 | input, 254 | optgroup, 255 | select, 256 | textarea { 257 | color: inherit; /* 1 */ 258 | font: inherit; /* 2 */ 259 | margin: 0; /* 3 */ 260 | } 261 | 262 | /** 263 | * Address `overflow` set to `hidden` in IE 8/9/10/11. 264 | */ 265 | 266 | button { 267 | overflow: visible; 268 | } 269 | 270 | /** 271 | * Address inconsistent `text-transform` inheritance for `button` and `select`. 272 | * All other form control elements do not inherit `text-transform` values. 273 | * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera. 274 | * Correct `select` style inheritance in Firefox. 275 | */ 276 | 277 | button, 278 | select { 279 | text-transform: none; 280 | } 281 | 282 | /** 283 | * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` 284 | * and `video` controls. 285 | * 2. Correct inability to style clickable `input` types in iOS. 286 | * 3. Improve usability and consistency of cursor style between image-type 287 | * `input` and others. 288 | */ 289 | 290 | button, 291 | html input[type="button"], /* 1 */ 292 | input[type="reset"], 293 | input[type="submit"] { 294 | -webkit-appearance: button; /* 2 */ 295 | cursor: pointer; /* 3 */ 296 | } 297 | 298 | /** 299 | * Re-set default cursor for disabled elements. 300 | */ 301 | 302 | button[disabled], 303 | html input[disabled] { 304 | cursor: default; 305 | } 306 | 307 | /** 308 | * Remove inner padding and border in Firefox 4+. 309 | */ 310 | 311 | button::-moz-focus-inner, 312 | input::-moz-focus-inner { 313 | border: 0; 314 | padding: 0; 315 | } 316 | 317 | /** 318 | * Address Firefox 4+ setting `line-height` on `input` using `!important` in 319 | * the UA stylesheet. 320 | */ 321 | 322 | input { 323 | line-height: normal; 324 | } 325 | 326 | /** 327 | * It's recommended that you don't attempt to style these elements. 328 | * Firefox's implementation doesn't respect box-sizing, padding, or width. 329 | * 330 | * 1. Address box sizing set to `content-box` in IE 8/9/10. 331 | * 2. Remove excess padding in IE 8/9/10. 332 | */ 333 | 334 | input[type="checkbox"], 335 | input[type="radio"] { 336 | box-sizing: border-box; /* 1 */ 337 | padding: 0; /* 2 */ 338 | } 339 | 340 | /** 341 | * Fix the cursor style for Chrome's increment/decrement buttons. For certain 342 | * `font-size` values of the `input`, it causes the cursor style of the 343 | * decrement button to change from `default` to `text`. 344 | */ 345 | 346 | input[type="number"]::-webkit-inner-spin-button, 347 | input[type="number"]::-webkit-outer-spin-button { 348 | height: auto; 349 | } 350 | 351 | /** 352 | * 1. Address `appearance` set to `searchfield` in Safari and Chrome. 353 | * 2. Address `box-sizing` set to `border-box` in Safari and Chrome 354 | * (include `-moz` to future-proof). 355 | */ 356 | 357 | input[type="search"] { 358 | -webkit-appearance: textfield; /* 1 */ 359 | -moz-box-sizing: content-box; 360 | -webkit-box-sizing: content-box; /* 2 */ 361 | box-sizing: content-box; 362 | } 363 | 364 | /** 365 | * Remove inner padding and search cancel button in Safari and Chrome on OS X. 366 | * Safari (but not Chrome) clips the cancel button when the search input has 367 | * padding (and `textfield` appearance). 368 | */ 369 | 370 | input[type="search"]::-webkit-search-cancel-button, 371 | input[type="search"]::-webkit-search-decoration { 372 | -webkit-appearance: none; 373 | } 374 | 375 | /** 376 | * Define consistent border, margin, and padding. 377 | */ 378 | 379 | fieldset { 380 | border: 1px solid #c0c0c0; 381 | margin: 0 2px; 382 | padding: 0.35em 0.625em 0.75em; 383 | } 384 | 385 | /** 386 | * 1. Correct `color` not being inherited in IE 8/9/10/11. 387 | * 2. Remove padding so people aren't caught out if they zero out fieldsets. 388 | */ 389 | 390 | legend { 391 | border: 0; /* 1 */ 392 | padding: 0; /* 2 */ 393 | } 394 | 395 | /** 396 | * Remove default vertical scrollbar in IE 8/9/10/11. 397 | */ 398 | 399 | textarea { 400 | overflow: auto; 401 | } 402 | 403 | /** 404 | * Don't inherit the `font-weight` (applied by a rule above). 405 | * NOTE: the default cannot safely be changed in Chrome and Safari on OS X. 406 | */ 407 | 408 | optgroup { 409 | font-weight: bold; 410 | } 411 | 412 | /* Tables 413 | ========================================================================== */ 414 | 415 | /** 416 | * Remove most spacing between table cells. 417 | */ 418 | 419 | table { 420 | border-collapse: collapse; 421 | border-spacing: 0; 422 | } 423 | 424 | td, 425 | th { 426 | padding: 0; 427 | } -------------------------------------------------------------------------------- /src/registerServiceWorker.js: -------------------------------------------------------------------------------- 1 | // In production, we register a service worker to serve assets from local cache. 2 | 3 | // This lets the app load faster on subsequent visits in production, and gives 4 | // it offline capabilities. However, it also means that developers (and users) 5 | // will only see deployed updates on the "N+1" visit to a page, since previously 6 | // cached resources are updated in the background. 7 | 8 | // To learn more about the benefits of this model, read https://goo.gl/KwvDNy. 9 | // This link also includes instructions on opting out of this behavior. 10 | 11 | const isLocalhost = Boolean( 12 | window.location.hostname === 'localhost' || 13 | // [::1] is the IPv6 localhost address. 14 | window.location.hostname === '[::1]' || 15 | // 127.0.0.1/8 is considered localhost for IPv4. 16 | window.location.hostname.match( 17 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ 18 | ) 19 | ); 20 | 21 | export default function register() { 22 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { 23 | // The URL constructor is available in all browsers that support SW. 24 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location); 25 | if (publicUrl.origin !== window.location.origin) { 26 | // Our service worker won't work if PUBLIC_URL is on a different origin 27 | // from what our page is served on. This might happen if a CDN is used to 28 | // serve assets; see https://github.com/facebookincubator/create-react-app/issues/2374 29 | return; 30 | } 31 | 32 | window.addEventListener('load', () => { 33 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; 34 | 35 | if (!isLocalhost) { 36 | // Is not local host. Just register service worker 37 | registerValidSW(swUrl); 38 | } else { 39 | // This is running on localhost. Lets check if a service worker still exists or not. 40 | checkValidServiceWorker(swUrl); 41 | } 42 | }); 43 | } 44 | } 45 | 46 | function registerValidSW(swUrl) { 47 | navigator.serviceWorker 48 | .register(swUrl) 49 | .then(registration => { 50 | registration.onupdatefound = () => { 51 | const installingWorker = registration.installing; 52 | installingWorker.onstatechange = () => { 53 | if (installingWorker.state === 'installed') { 54 | if (navigator.serviceWorker.controller) { 55 | // At this point, the old content will have been purged and 56 | // the fresh content will have been added to the cache. 57 | // It's the perfect time to display a "New content is 58 | // available; please refresh." message in your web app. 59 | console.log('New content is available; please refresh.'); 60 | } else { 61 | // At this point, everything has been precached. 62 | // It's the perfect time to display a 63 | // "Content is cached for offline use." message. 64 | console.log('Content is cached for offline use.'); 65 | } 66 | } 67 | }; 68 | }; 69 | }) 70 | .catch(error => { 71 | console.error('Error during service worker registration:', error); 72 | }); 73 | } 74 | 75 | function checkValidServiceWorker(swUrl) { 76 | // Check if the service worker can be found. If it can't reload the page. 77 | fetch(swUrl) 78 | .then(response => { 79 | // Ensure service worker exists, and that we really are getting a JS file. 80 | if ( 81 | response.status === 404 || 82 | response.headers.get('content-type').indexOf('javascript') === -1 83 | ) { 84 | // No service worker found. Probably a different app. Reload the page. 85 | navigator.serviceWorker.ready.then(registration => { 86 | registration.unregister().then(() => { 87 | window.location.reload(); 88 | }); 89 | }); 90 | } else { 91 | // Service worker found. Proceed as normal. 92 | registerValidSW(swUrl); 93 | } 94 | }) 95 | .catch(() => { 96 | console.log( 97 | 'No internet connection found. App is running in offline mode.' 98 | ); 99 | }); 100 | } 101 | 102 | export function unregister() { 103 | if ('serviceWorker' in navigator) { 104 | navigator.serviceWorker.ready.then(registration => { 105 | registration.unregister(); 106 | }); 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/skeleton.css: -------------------------------------------------------------------------------- 1 | /* 2 | * Skeleton V2.0.4 3 | * Copyright 2014, Dave Gamache 4 | * www.getskeleton.com 5 | * Free to use under the MIT license. 6 | * http://www.opensource.org/licenses/mit-license.php 7 | * 12/29/2014 8 | */ 9 | 10 | 11 | /* Table of contents 12 | –––––––––––––––––––––––––––––––––––––––––––––––––– 13 | - Grid 14 | - Base Styles 15 | - Typography 16 | - Links 17 | - Buttons 18 | - Forms 19 | - Lists 20 | - Code 21 | - Tables 22 | - Spacing 23 | - Utilities 24 | - Clearing 25 | - Media Queries 26 | */ 27 | 28 | 29 | /* Grid 30 | –––––––––––––––––––––––––––––––––––––––––––––––––– */ 31 | .container { 32 | position: relative; 33 | width: 100%; 34 | max-width: 960px; 35 | margin: 0 auto; 36 | padding: 0 20px; 37 | box-sizing: border-box; } 38 | .column, 39 | .columns { 40 | width: 100%; 41 | float: left; 42 | box-sizing: border-box; } 43 | 44 | /* For devices larger than 400px */ 45 | @media (min-width: 400px) { 46 | .container { 47 | width: 85%; 48 | padding: 0; } 49 | } 50 | 51 | /* For devices larger than 550px */ 52 | @media (min-width: 550px) { 53 | .container { 54 | width: 80%; } 55 | .column, 56 | .columns { 57 | margin-left: 4%; } 58 | .column:first-child, 59 | .columns:first-child { 60 | margin-left: 0; } 61 | 62 | .one.column, 63 | .one.columns { width: 4.66666666667%; } 64 | .two.columns { width: 13.3333333333%; } 65 | .three.columns { width: 22%; } 66 | .four.columns { width: 30.6666666667%; } 67 | .five.columns { width: 39.3333333333%; } 68 | .six.columns { width: 48%; } 69 | .seven.columns { width: 56.6666666667%; } 70 | .eight.columns { width: 65.3333333333%; } 71 | .nine.columns { width: 74.0%; } 72 | .ten.columns { width: 82.6666666667%; } 73 | .eleven.columns { width: 91.3333333333%; } 74 | .twelve.columns { width: 100%; margin-left: 0; } 75 | 76 | .one-third.column { width: 30.6666666667%; } 77 | .two-thirds.column { width: 65.3333333333%; } 78 | 79 | .one-half.column { width: 48%; } 80 | 81 | /* Offsets */ 82 | .offset-by-one.column, 83 | .offset-by-one.columns { margin-left: 8.66666666667%; } 84 | .offset-by-two.column, 85 | .offset-by-two.columns { margin-left: 17.3333333333%; } 86 | .offset-by-three.column, 87 | .offset-by-three.columns { margin-left: 26%; } 88 | .offset-by-four.column, 89 | .offset-by-four.columns { margin-left: 34.6666666667%; } 90 | .offset-by-five.column, 91 | .offset-by-five.columns { margin-left: 43.3333333333%; } 92 | .offset-by-six.column, 93 | .offset-by-six.columns { margin-left: 52%; } 94 | .offset-by-seven.column, 95 | .offset-by-seven.columns { margin-left: 60.6666666667%; } 96 | .offset-by-eight.column, 97 | .offset-by-eight.columns { margin-left: 69.3333333333%; } 98 | .offset-by-nine.column, 99 | .offset-by-nine.columns { margin-left: 78.0%; } 100 | .offset-by-ten.column, 101 | .offset-by-ten.columns { margin-left: 86.6666666667%; } 102 | .offset-by-eleven.column, 103 | .offset-by-eleven.columns { margin-left: 95.3333333333%; } 104 | 105 | .offset-by-one-third.column, 106 | .offset-by-one-third.columns { margin-left: 34.6666666667%; } 107 | .offset-by-two-thirds.column, 108 | .offset-by-two-thirds.columns { margin-left: 69.3333333333%; } 109 | 110 | .offset-by-one-half.column, 111 | .offset-by-one-half.columns { margin-left: 52%; } 112 | 113 | } 114 | 115 | 116 | /* Base Styles 117 | –––––––––––––––––––––––––––––––––––––––––––––––––– */ 118 | /* NOTE 119 | html is set to 62.5% so that all the REM measurements throughout Skeleton 120 | are based on 10px sizing. So basically 1.5rem = 15px :) */ 121 | html { 122 | font-size: 62.5%; } 123 | body { 124 | font-size: 1.5em; /* currently ems cause chrome bug misinterpreting rems on body element */ 125 | line-height: 1.6; 126 | font-weight: 400; 127 | font-family: "Raleway", "HelveticaNeue", "Helvetica Neue", Helvetica, Arial, sans-serif; 128 | color: #222; } 129 | 130 | 131 | /* Typography 132 | –––––––––––––––––––––––––––––––––––––––––––––––––– */ 133 | h1, h2, h3, h4, h5, h6 { 134 | margin-top: 0; 135 | margin-bottom: 2rem; 136 | font-weight: 300; } 137 | h1 { font-size: 4.0rem; line-height: 1.2; letter-spacing: -.1rem;} 138 | h2 { font-size: 3.6rem; line-height: 1.25; letter-spacing: -.1rem; } 139 | h3 { font-size: 3.0rem; line-height: 1.3; letter-spacing: -.1rem; } 140 | h4 { font-size: 2.4rem; line-height: 1.35; letter-spacing: -.08rem; } 141 | h5 { font-size: 1.8rem; line-height: 1.5; letter-spacing: -.05rem; } 142 | h6 { font-size: 1.5rem; line-height: 1.6; letter-spacing: 0; } 143 | 144 | /* Larger than phablet */ 145 | @media (min-width: 550px) { 146 | h1 { font-size: 5.0rem; } 147 | h2 { font-size: 4.2rem; } 148 | h3 { font-size: 3.6rem; } 149 | h4 { font-size: 3.0rem; } 150 | h5 { font-size: 2.4rem; } 151 | h6 { font-size: 1.5rem; } 152 | } 153 | 154 | p { 155 | margin-top: 0; } 156 | 157 | 158 | /* Links 159 | –––––––––––––––––––––––––––––––––––––––––––––––––– */ 160 | a { 161 | color: #1EAEDB; } 162 | a:hover { 163 | color: #0FA0CE; } 164 | 165 | 166 | /* Buttons 167 | –––––––––––––––––––––––––––––––––––––––––––––––––– */ 168 | .button, 169 | button, 170 | input[type="submit"], 171 | input[type="reset"], 172 | input[type="button"] { 173 | display: inline-block; 174 | height: 38px; 175 | padding: 0 30px; 176 | color: #555; 177 | text-align: center; 178 | font-size: 11px; 179 | font-weight: 600; 180 | line-height: 38px; 181 | letter-spacing: .1rem; 182 | text-transform: uppercase; 183 | text-decoration: none; 184 | white-space: nowrap; 185 | background-color: transparent; 186 | border-radius: 4px; 187 | border: 1px solid #bbb; 188 | cursor: pointer; 189 | box-sizing: border-box; } 190 | .button:hover, 191 | button:hover, 192 | input[type="submit"]:hover, 193 | input[type="reset"]:hover, 194 | input[type="button"]:hover, 195 | .button:focus, 196 | button:focus, 197 | input[type="submit"]:focus, 198 | input[type="reset"]:focus, 199 | input[type="button"]:focus { 200 | color: #333; 201 | border-color: #888; 202 | outline: 0; } 203 | .button.button-primary, 204 | button.button-primary, 205 | input[type="submit"].button-primary, 206 | input[type="reset"].button-primary, 207 | input[type="button"].button-primary { 208 | color: #FFF; 209 | background-color: #33C3F0; 210 | border-color: #33C3F0; } 211 | .button.button-primary:hover, 212 | button.button-primary:hover, 213 | input[type="submit"].button-primary:hover, 214 | input[type="reset"].button-primary:hover, 215 | input[type="button"].button-primary:hover, 216 | .button.button-primary:focus, 217 | button.button-primary:focus, 218 | input[type="submit"].button-primary:focus, 219 | input[type="reset"].button-primary:focus, 220 | input[type="button"].button-primary:focus { 221 | color: #FFF; 222 | background-color: #1EAEDB; 223 | border-color: #1EAEDB; } 224 | 225 | 226 | /* Forms 227 | –––––––––––––––––––––––––––––––––––––––––––––––––– */ 228 | input[type="email"], 229 | input[type="number"], 230 | input[type="search"], 231 | input[type="text"], 232 | input[type="tel"], 233 | input[type="url"], 234 | input[type="password"], 235 | textarea, 236 | select { 237 | height: 38px; 238 | padding: 6px 10px; /* The 6px vertically centers text on FF, ignored by Webkit */ 239 | background-color: #fff; 240 | border: 1px solid #D1D1D1; 241 | border-radius: 4px; 242 | box-shadow: none; 243 | box-sizing: border-box; } 244 | /* Removes awkward default styles on some inputs for iOS */ 245 | input[type="email"], 246 | input[type="number"], 247 | input[type="search"], 248 | input[type="text"], 249 | input[type="tel"], 250 | input[type="url"], 251 | input[type="password"], 252 | textarea { 253 | -webkit-appearance: none; 254 | -moz-appearance: none; 255 | appearance: none; } 256 | textarea { 257 | min-height: 65px; 258 | padding-top: 6px; 259 | padding-bottom: 6px; } 260 | input[type="email"]:focus, 261 | input[type="number"]:focus, 262 | input[type="search"]:focus, 263 | input[type="text"]:focus, 264 | input[type="tel"]:focus, 265 | input[type="url"]:focus, 266 | input[type="password"]:focus, 267 | textarea:focus, 268 | select:focus { 269 | border: 1px solid #33C3F0; 270 | outline: 0; } 271 | label, 272 | legend { 273 | display: block; 274 | margin-bottom: .5rem; 275 | font-weight: 600; } 276 | fieldset { 277 | padding: 0; 278 | border-width: 0; } 279 | input[type="checkbox"], 280 | input[type="radio"] { 281 | display: inline; } 282 | label > .label-body { 283 | display: inline-block; 284 | margin-left: .5rem; 285 | font-weight: normal; } 286 | 287 | 288 | /* Lists 289 | –––––––––––––––––––––––––––––––––––––––––––––––––– */ 290 | ul { 291 | list-style: circle inside; } 292 | ol { 293 | list-style: decimal inside; } 294 | ol, ul { 295 | padding-left: 0; 296 | margin-top: 0; } 297 | ul ul, 298 | ul ol, 299 | ol ol, 300 | ol ul { 301 | margin: 1.5rem 0 1.5rem 3rem; 302 | font-size: 90%; } 303 | li { 304 | margin-bottom: 1rem; } 305 | 306 | 307 | /* Code 308 | –––––––––––––––––––––––––––––––––––––––––––––––––– */ 309 | code { 310 | padding: .2rem .5rem; 311 | margin: 0 .2rem; 312 | font-size: 90%; 313 | white-space: nowrap; 314 | background: #F1F1F1; 315 | border: 1px solid #E1E1E1; 316 | border-radius: 4px; } 317 | pre > code { 318 | display: block; 319 | padding: 1rem 1.5rem; 320 | white-space: pre; } 321 | 322 | 323 | /* Tables 324 | –––––––––––––––––––––––––––––––––––––––––––––––––– */ 325 | th, 326 | td { 327 | padding: 12px 15px; 328 | text-align: left; 329 | border-bottom: 1px solid #E1E1E1; } 330 | th:first-child, 331 | td:first-child { 332 | padding-left: 0; } 333 | th:last-child, 334 | td:last-child { 335 | padding-right: 0; } 336 | 337 | 338 | /* Spacing 339 | –––––––––––––––––––––––––––––––––––––––––––––––––– */ 340 | button, 341 | .button { 342 | margin-bottom: 1rem; } 343 | input, 344 | textarea, 345 | select, 346 | fieldset { 347 | margin-bottom: 1.5rem; } 348 | pre, 349 | blockquote, 350 | dl, 351 | figure, 352 | table, 353 | p, 354 | ul, 355 | ol, 356 | form { 357 | margin-bottom: 2.5rem; } 358 | 359 | 360 | /* Utilities 361 | –––––––––––––––––––––––––––––––––––––––––––––––––– */ 362 | .u-full-width { 363 | width: 100%; 364 | box-sizing: border-box; } 365 | .u-max-full-width { 366 | max-width: 100%; 367 | box-sizing: border-box; } 368 | .u-pull-right { 369 | float: right; } 370 | .u-pull-left { 371 | float: left; } 372 | 373 | 374 | /* Misc 375 | –––––––––––––––––––––––––––––––––––––––––––––––––– */ 376 | hr { 377 | margin-top: 3rem; 378 | margin-bottom: 3.5rem; 379 | border-width: 0; 380 | border-top: 1px solid #E1E1E1; } 381 | 382 | 383 | /* Clearing 384 | –––––––––––––––––––––––––––––––––––––––––––––––––– */ 385 | 386 | /* Self Clearing Goodness */ 387 | .container:after, 388 | .row:after, 389 | .u-cf { 390 | content: ""; 391 | display: table; 392 | clear: both; } 393 | 394 | 395 | /* Media Queries 396 | –––––––––––––––––––––––––––––––––––––––––––––––––– */ 397 | /* 398 | Note: The best way to structure the use of media queries is to create the queries 399 | near the relevant code. For example, if you wanted to change the styles for buttons 400 | on small devices, paste the mobile query code up in the buttons section and style it 401 | there. 402 | */ 403 | 404 | 405 | /* Larger than mobile */ 406 | @media (min-width: 400px) {} 407 | 408 | /* Larger than phablet (also point when grid becomes active) */ 409 | @media (min-width: 550px) {} 410 | 411 | /* Larger than tablet */ 412 | @media (min-width: 750px) {} 413 | 414 | /* Larger than desktop */ 415 | @media (min-width: 1000px) {} 416 | 417 | /* Larger than Desktop HD */ 418 | @media (min-width: 1200px) {} 419 | -------------------------------------------------------------------------------- /src/toolbarPlugin.css: -------------------------------------------------------------------------------- 1 | .headlineButtonWrapper { 2 | display: inline-block; 3 | } 4 | 5 | .headlineButton { 6 | color: #888; 7 | font-size: 18px; 8 | border: 0; 9 | vertical-align: bottom; 10 | border-radius: 0px; 11 | 12 | } 13 | 14 | .headlineButton:hover, 15 | .headlineButton:focus { 16 | background: #f3f3f3; 17 | } 18 | 19 | .draftJsToolbar__buttonWrapper__1Dmqh { 20 | display: inline-block; 21 | } 22 | 23 | .draftJsToolbar__button__qi1gf { 24 | /*margin: 0px;*/ 25 | padding: 0 16px; 26 | line-height: initial; 27 | border: none; 28 | /*position: relative; 29 | top: -11px;*/ 30 | border-radius: 0px; 31 | vertical-align: bottom; 32 | /*background: #fbfbfb; 33 | color: #888; 34 | font-size: 18px; 35 | border: 0; 36 | padding-top: 5px; 37 | vertical-align: bottom; 38 | height: 34px; 39 | width: 36px; 40 | margin: 0px; 41 | 42 | height: 100%; 43 | border-radius: 0px; 44 | border: 0px; 45 | padding-top: 6px; 46 | padding-left: 15px; 47 | width: 50px;*/ 48 | } 49 | 50 | .draftJsToolbar__button__qi1gf svg { 51 | fill: #888; 52 | } 53 | 54 | .draftJsToolbar__button__qi1gf:hover, .draftJsToolbar__button__qi1gf:focus { 55 | background: #f3f3f3; 56 | outline: 0; /* reset for :focus */ 57 | } 58 | 59 | .draftJsToolbar__active__3qcpF { 60 | background: #efefef; 61 | color: #444; 62 | } 63 | 64 | .draftJsToolbar__active__3qcpF svg { 65 | fill: #444; 66 | } 67 | .draftJsToolbar__separator__3U7qt { 68 | display: inline-block; 69 | border-right: 1px solid #ddd; 70 | height: 24px; 71 | margin: 0 0.5em; 72 | } 73 | .draftJsToolbar__toolbar__dNtBH { 74 | border: 1px solid #ddd; 75 | background: #fff; 76 | box-shadow: 0px 1px 3px 0px rgba(220,220,220,1); 77 | z-index: 2; 78 | box-sizing: border-box; 79 | 80 | height: 40px; 81 | } 82 | 83 | .draftJsToolbar__toolbar__dNtBH:after { 84 | border-color: rgba(255, 255, 255, 0); 85 | border-top-color: #fff; 86 | border-width: 4px; 87 | margin-left: -4px; 88 | } 89 | .draftJsToolbar__toolbar__dNtBH:before { 90 | border-color: rgba(221, 221, 221, 0); 91 | border-top-color: #ddd; 92 | border-width: 6px; 93 | margin-left: -6px; 94 | } --------------------------------------------------------------------------------