Repository: MattMcFarland/reactathon Branch: master Commit: c35837d58488 Files: 178 Total size: 2.3 MB Directory structure: gitextract_uwmvxg_y/ ├── .babelrc ├── .editorconfig ├── .eslintignore ├── .eslintrc ├── .flowconfig ├── .gitignore ├── LICENSE ├── README.md ├── client/ │ ├── client-manifest.json │ ├── gulpCompressionOptions.js │ └── src/ │ ├── Layout.js │ ├── __tests__/ │ │ └── ok.js │ ├── actions/ │ │ └── AppActions.js │ ├── alt.js │ ├── components/ │ │ ├── AddNewArticleForm.js │ │ ├── LoginForm.js │ │ ├── ResetPasswordForm.js │ │ ├── ResetRequestForm.js │ │ ├── SignupForm.js │ │ ├── index.js │ │ └── partials/ │ │ ├── Elements.js │ │ ├── FormErrors.js │ │ └── index.js │ ├── containers/ │ │ ├── AddNewArticle.js │ │ ├── Article.js │ │ ├── ArticleList.js │ │ ├── Dashboard.js │ │ ├── Home.js │ │ ├── Login.js │ │ ├── NoMatch.js │ │ ├── Page.js │ │ ├── ResetPassword.js │ │ ├── ResetRequest.js │ │ ├── SignUp.js │ │ ├── Tag.js │ │ ├── TagList.js │ │ ├── User.js │ │ └── index.js │ ├── main.js │ ├── queries/ │ │ ├── ViewerQueries.js │ │ └── index.js │ ├── stores/ │ │ └── AppStore.js │ └── style/ │ ├── base/ │ │ ├── _transitions.scss │ │ └── _variables.scss │ ├── main.scss │ ├── objects/ │ │ └── _buttons.scss │ └── vendor/ │ ├── _bootstrap.scss │ └── bootstrap/ │ ├── _alerts.scss │ ├── _badges.scss │ ├── _breadcrumbs.scss │ ├── _button-groups.scss │ ├── _buttons.scss │ ├── _carousel.scss │ ├── _close.scss │ ├── _code.scss │ ├── _component-animations.scss │ ├── _dropdowns.scss │ ├── _forms.scss │ ├── _glyphicons.scss │ ├── _grid.scss │ ├── _input-groups.scss │ ├── _jumbotron.scss │ ├── _labels.scss │ ├── _list-group.scss │ ├── _media.scss │ ├── _mixins.scss │ ├── _modals.scss │ ├── _navbar.scss │ ├── _navs.scss │ ├── _normalize.scss │ ├── _pager.scss │ ├── _pagination.scss │ ├── _panels.scss │ ├── _popovers.scss │ ├── _print.scss │ ├── _progress-bars.scss │ ├── _responsive-embed.scss │ ├── _responsive-utilities.scss │ ├── _scaffolding.scss │ ├── _tables.scss │ ├── _theme.scss │ ├── _thumbnails.scss │ ├── _tooltip.scss │ ├── _type.scss │ ├── _utilities.scss │ ├── _variables.scss │ ├── _wells.scss │ └── mixins/ │ ├── _alerts.scss │ ├── _background-variant.scss │ ├── _border-radius.scss │ ├── _buttons.scss │ ├── _center-block.scss │ ├── _clearfix.scss │ ├── _forms.scss │ ├── _gradients.scss │ ├── _grid-framework.scss │ ├── _grid.scss │ ├── _hide-text.scss │ ├── _image.scss │ ├── _labels.scss │ ├── _list-group.scss │ ├── _nav-divider.scss │ ├── _nav-vertical-align.scss │ ├── _opacity.scss │ ├── _pagination.scss │ ├── _panels.scss │ ├── _progress-bar.scss │ ├── _reset-filter.scss │ ├── _reset-text.scss │ ├── _resize.scss │ ├── _responsive-visibility.scss │ ├── _size.scss │ ├── _tab-focus.scss │ ├── _table-row.scss │ ├── _text-emphasis.scss │ ├── _text-overflow.scss │ └── _vendor-prefixes.scss ├── data/ │ ├── schema.graphql │ └── schema.json ├── ecosystem.json ├── gulpfile.js ├── mediakit/ │ └── reactathon.ai ├── package.json ├── scripts/ │ ├── babelRelayPlugin.js │ ├── mocha-bootload.js │ ├── seed.js │ ├── server.js │ └── updateSchema.js ├── server/ │ └── src/ │ ├── __tests__/ │ │ └── testModules.js │ ├── app.config.js │ ├── app.js │ ├── auth/ │ │ ├── index.js │ │ ├── modules.js │ │ └── passport.js │ ├── database/ │ │ ├── index.js │ │ ├── migrations/ │ │ │ └── .gitkeep │ │ ├── models/ │ │ │ ├── Article.js │ │ │ ├── Comment.js │ │ │ ├── Flag.js │ │ │ ├── Tag.js │ │ │ ├── TagItem.js │ │ │ ├── Token.js │ │ │ ├── User.js │ │ │ ├── Vote.js │ │ │ ├── customTypes/ │ │ │ │ ├── URL.js │ │ │ │ ├── email.js │ │ │ │ └── index.js │ │ │ └── index.js │ │ ├── modules.js │ │ └── seeders/ │ │ └── .gitkeep │ ├── modules.js │ ├── pages/ │ │ └── about.md │ ├── public/ │ │ ├── browserconfig.xml │ │ ├── img/ │ │ │ └── .gitkeep │ │ └── manifest.json │ ├── routes/ │ │ ├── api.js │ │ ├── auth.js │ │ ├── index.js │ │ ├── modules.js │ │ └── root.js │ ├── schema/ │ │ └── index.js │ ├── utils/ │ │ ├── fromGravatar.js │ │ ├── getGravatar.js │ │ ├── index.js │ │ ├── logger.js │ │ └── modules.js │ └── views/ │ ├── error.hbs │ ├── index.hbs │ ├── layout.hbs │ └── root.hbs ├── ssl/ │ ├── localhost.cert │ └── localhost.key └── tasks/ ├── bundle.js ├── bundledebugdeps.js ├── bundledeps.js ├── bundlemin.js ├── helpers.js └── sass.js ================================================ FILE CONTENTS ================================================ ================================================ FILE: .babelrc ================================================ { "presets": ["es2015", "stage-0", "react"], "plugins": ["transform-flow-strip-types", "babel-relay-plugin-loader"] } ================================================ FILE: .editorconfig ================================================ ; http://editorconfig.org root = true [*.js] indent_style = space indent_size = 2 end_of_line = lf charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true [*.md] indent_size = 2 [*.html] indent_size = 2 [*.hbs] indent_size = 2 ================================================ FILE: .eslintignore ================================================ ./flow/**/* ./tasks/**/* ./scripts/**/* ================================================ FILE: .eslintrc ================================================ { "parser": "babel-eslint", "parserOptions": { "ecmaFeatures": { "jsx": true } }, "plugins": [ "react" ], "arrowFunctions": true, "blockBindings": true, "classes": true, "defaultParams": true, "destructuring": true, "forOf": true, "generators": true, "modules": true, "objectLiteralComputedProperties": true, "objectLiteralShorthandMethods": true, "objectLiteralShorthandProperties": true, "spread": true, "templateStrings": true, "env": { "browser": true, "node": true, "es6": true }, "rules": { "react/display-name": [2, { "acceptTranspilerName": true }], "react/forbid-prop-types": [2, { "forbid": [] }], "react/jsx-boolean-value": [2, "never"], "react/jsx-closing-bracket-location": [2, "after-props"], "react/jsx-curly-spacing": [2, "never"], "react/jsx-handler-names": [0, { "eventHandlerPrefix": "handle", "eventHandlerPropPrefix": "on" }], "react/jsx-indent-props": [0, "1"], "react/jsx-key": 2, "react/jsx-max-props-per-line": [2, { "maximum": 4 }], "react/jsx-no-bind": 2, "react/jsx-no-duplicate-props": 2, "react/jsx-no-literals": 0, "react/jsx-no-undef": 2, "react/jsx-pascal-case": 2, "react/jsx-sort-prop-types": 0, "react/jsx-sort-props": 0, "react/jsx-uses-react": 2, "react/jsx-uses-vars": 2, "react/no-danger": 0, "react/no-did-mount-set-state": 2, "react/no-did-update-set-state": 2, "react/no-direct-mutation-state": 2, "react/no-multi-comp": 0, "react/no-set-state": 0, "react/no-unknown-property": 2, "react/prefer-es6-class": 2, "react/prop-types": 0, "react/react-in-jsx-scope": 2, "react/require-extension": 2, "react/self-closing-comp": 2, "react/sort-comp": 0, "react/wrap-multilines": 2, "comma-dangle": 0, "no-cond-assign": 2, "no-console": 0, "no-constant-condition": 2, "no-control-regex": 0, "no-debugger": 0, "no-dupe-args": 2, "no-dupe-keys": 2, "no-duplicate-case": 2, "no-empty": 2, "no-empty-character-class": 2, "no-ex-assign": 2, "no-extra-boolean-cast": 2, "no-extra-semi": 2, "no-func-assign": 2, "no-inner-declarations": [ 2, "functions" ], "no-invalid-regexp": 2, "no-irregular-whitespace": 2, "no-negated-in-lhs": 2, "no-obj-calls": 2, "no-regex-spaces": 2, "no-reserved-keys": 0, "no-sparse-arrays": 2, "no-unreachable": 2, "use-isnan": 2, "valid-jsdoc": 0, "valid-typeof": 2, "block-scoped-var": 0, "complexity": 0, "consistent-return": 0, "curly": [ 2, "all" ], "default-case": 0, "dot-notation": 0, "eqeqeq": 2, "guard-for-in": 2, "no-alert": 2, "no-caller": 2, "no-div-regex": 2, "no-empty-label": 2, "no-eq-null": 0, "no-eval": 2, "no-extend-native": 2, "no-extra-bind": 2, "no-fallthrough": 2, "no-floating-decimal": 2, "no-implied-eval": 2, "no-iterator": 2, "no-labels": 0, "no-lone-blocks": 0, "no-loop-func": 0, "no-multi-spaces": 2, "no-multi-str": 2, "no-native-reassign": 0, "no-new": 2, "no-new-func": 0, "no-new-wrappers": 2, "no-octal": 2, "no-octal-escape": 2, "no-param-reassign": 2, "no-process-env": 0, "no-proto": 2, "no-redeclare": 2, "no-return-assign": 2, "no-script-url": 2, "no-self-compare": 0, "no-sequences": 2, "no-throw-literal": 2, "no-unused-expressions": 2, "no-void": 2, "no-warning-comments": 0, "no-with": 2, "radix": [2, "as-needed"], "vars-on-top": 0, "wrap-iife": 2, "yoda": [ 2, "never", { "exceptRange": true } ], "strict": 0, "no-catch-shadow": 2, "no-delete-var": 2, "no-label-var": 2, "no-shadow": 2, "no-shadow-restricted-names": 2, "no-undef": 2, "no-undef-init": 2, "no-undefined": 0, "no-unused-vars": [ 2, { "vars": "all", "args": "after-used", "varsIgnorePattern": "React|Relay" } ], "no-use-before-define": 0, "handle-callback-err": [ 2, "error" ], "no-mixed-requires": [ 2, true ], "no-new-require": 2, "no-path-concat": 2, "no-process-exit": 0, "no-restricted-modules": 0, "no-sync": 0, "brace-style": [ 2, "1tbs", { "allowSingleLine": true } ], "comma-spacing": 0, "comma-style": [ 2, "last" ], "consistent-this": 0, "eol-last": 2, "func-names": 0, "func-style": 0, "key-spacing": [ 2, { "beforeColon": false, "afterColon": true } ], "max-nested-callbacks": 0, "new-cap": 0, "new-parens": 2, "newline-after-var": 0, "no-array-constructor": 2, "no-inline-comments": 0, "no-lonely-if": 2, "no-mixed-spaces-and-tabs": 2, "no-multiple-empty-lines": 0, "no-nested-ternary": 0, "no-new-object": 2, "no-spaced-func": 2, "no-ternary": 0, "no-trailing-spaces": 0, "no-underscore-dangle": 0, "one-var": [ 2, "never" ], "operator-assignment": [ 2, "always" ], "padded-blocks": 0, "quote-props": [ 2, "as-needed" ], "quotes": [ 2, "single" ], "semi": [ 2, "always" ], "semi-spacing": [ 2, { "before": false, "after": true } ], "sort-vars": 0, "space-after-keywords": [ 2, "always" ], "space-before-blocks": [ 2, "always" ], "space-before-function-paren": [ 2, { "anonymous": "always", "named": "never" } ], "space-in-brackets": 0, "space-in-parens": 0, "space-infix-ops": [ 2, { "int32Hint": false } ], "space-return-throw-case": 2, "space-unary-ops": [ 2, { "words": true, "nonwords": false } ], "spaced-comment": [ 2, "always" ], "wrap-regex": 0, "no-var": 0, "max-len": [2, 80, 4] } } ================================================ FILE: .flowconfig ================================================ [ignore] .*/coverage/.* .*/scripts/.* .*/node_modules/.* .*/public/.* .*/dist/.* [include] [libs] flow [options] ================================================ FILE: .gitignore ================================================ # Created by .ignore support plugin (hsz.mobi) ### Emacs template # -*- mode: gitignore; -*- \#*\# /.emacs.desktop /.emacs.desktop.lock *.elc auto-save-list tramp .\#* # Org-mode .org-id-locations *_archive # flymake-mode *_flymake.* # eshell files /eshell/history /eshell/lastdir # elpa packages /elpa/ # reftex files *.rel # AUCTeX auto folder /auto/ # cask packages .cask/ ### VisualStudio template ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. # User-specific files *.suo *.user *.userosscache *.sln.docstates # User-specific files (MonoDevelop/Xamarin Studio) *.userprefs # Build results [Dd]ebug/ [Dd]ebugPublic/ [Rr]elease/ [Rr]eleases/ x64/ x86/ build/ bld/ [Bb]in/ [Oo]bj/ # Visual Studio 2015 cache/options directory .vs/ # Uncomment if you have tasks that create the project's static files in wwwroot #wwwroot/ # MSTest test Results [Tt]est[Rr]esult*/ [Bb]uild[Ll]og.* # NUNIT *.VisualState.xml TestResult.xml # Build Results of an ATL Project [Dd]ebugPS/ [Rr]eleasePS/ dlldata.c # DNX project.lock.json artifacts/ *_i.c *_p.c *_i.h *.ilk *.meta *.obj *.pch *.pdb *.pgc *.pgd *.rsp *.sbr *.tlb *.tli *.tlh *.tmp *.vspscc *.vssscc .builds *.pidb *.svclog *.scc # Chutzpah Test files _Chutzpah* # Visual C++ cache files ipch/ *.aps *.ncb *.opensdf *.sdf *.cachefile # Visual Studio profiler *.psess *.vsp *.vspx # TFS 2012 Local Workspace $tf/ # Guidance Automation Toolkit *.gpState # ReSharper is a .NET coding add-in _ReSharper*/ *.[Rr]e[Ss]harper *.DotSettings.user # JustCode is a .NET coding add-in .JustCode # TeamCity is a build add-in _TeamCity* # DotCover is a Code Coverage Tool *.dotCover # NCrunch _NCrunch_* .*crunch*.local.xml nCrunchTemp_* # MightyMoose *.mm.* AutoTest.Net/ # Web workbench (sass) .sass-cache/ # Installshield output folder [Ee]xpress/ # DocProject is a documentation generator add-in DocProject/buildhelp/ DocProject/Help/*.HxT DocProject/Help/*.HxC DocProject/Help/*.hhc DocProject/Help/*.hhk DocProject/Help/*.hhp DocProject/Help/Html2 DocProject/Help/html # Click-Once directory publish/ # Publish Web Output *.[Pp]ublish.xml *.azurePubxml # but database connection strings (with potential passwords) will be unencrypted *.pubxml *.publishproj # NuGet Packages *.nupkg # The packages folder can be ignored because of Package Restore **/packages/* # except build/, which is used as an MSBuild target. !**/packages/build/ # Uncomment if necessary however generally it will be regenerated when needed #!**/packages/repositories.config # Windows Azure Build Output csx/ *.build.csdef # Windows Store app package directory AppPackages/ # Visual Studio cache files # files ending in .cache can be ignored *.[Cc]ache # but keep track of directories ending in .cache !*.[Cc]ache/ # Others *.dbmdl *.dbproj.schemaview *.pfx *.publishsettings node_modules/ orleans.codegen.cs # RIA/Silverlight projects Generated_Code/ # Backup & report files from converting an old project file # to a newer Visual Studio version. Backup files are not needed, # because we have git ;-) _UpgradeReport_Files/ Backup*/ UpgradeLog*.XML UpgradeLog*.htm # SQL Server files *.mdf *.ldf # Business Intelligence projects *.rdl.data *.bim.layout *.bim_*.settings # Microsoft Fakes FakesAssemblies/ # Node.js Tools for Visual Studio .ntvs_analysis.dat # Visual Studio 6 build log *.plg # Visual Studio 6 workspace options file *.opt # Visual Studio LightSwitch build output **/*.HTMLClient/GeneratedArtifacts **/*.DesktopClient/GeneratedArtifacts **/*.DesktopClient/ModelManifest.xml **/*.Server/GeneratedArtifacts **/*.Server/ModelManifest.xml _Pvt_Extensions ### Windows template # Windows image file caches Thumbs.db ehthumbs.db # Folder config file Desktop.ini # Recycle Bin used on file shares $RECYCLE.BIN/ # Windows Installer files *.cab *.msi *.msm *.msp # Windows shortcuts *.lnk ### Vim template [._]*.s[a-w][a-z] [._]s[a-w][a-z] *.un~ Session.vim .netrwhist ### Xcode template # Xcode # # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore ## Build generated DerivedData ## Various settings *.pbxuser !default.pbxuser *.mode1v3 !default.mode1v3 *.mode2v3 !default.mode2v3 *.perspectivev3 !default.perspectivev3 xcuserdata ## Other *.xccheckout *.moved-aside *.xcuserstate ### Node template # Logs logs npm-debug.log* # Runtime data pids *.pid *.seed # Directory for instrumented libs generated by jscoverage/JSCover lib-cov # Coverage directory used by tools like istanbul coverage # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) .grunt # node-waf configuration .lock-wscript # Compiled binary addons (http://nodejs.org/api/addons.html) build/Release # Dependency directory # https://docs.npmjs.com/misc/faq#should-i-check-my-node-modules-folder-into-git ### JetBrains template # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio ## Directory-based project format: .idea/ # if you remove the above rule, at least ignore the following: # User-specific stuff: # .idea/workspace.xml # .idea/tasks.xml # .idea/dictionaries # Sensitive or high-churn files: # .idea/dataSources.ids # .idea/dataSources.xml # .idea/sqlDataSources.xml # .idea/dynamic.xml # .idea/uiDesigner.xml # Gradle: # .idea/gradle.xml # .idea/libraries # Mongo Explorer plugin: # .idea/mongoSettings.xml ## File-based project format: *.ipr *.iws ## Plugin-specific files: # IntelliJ /out/ # mpeltonen/sbt-idea plugin .idea_modules/ # JIRA plugin atlassian-ide-plugin.xml # Crashlytics plugin (for Android Studio and IntelliJ) com_crashlytics_export_strings.xml crashlytics.properties crashlytics-build.properties ### Cloud9 template # Cloud9 IDE - http://c9.io .c9revisions .c9 ### Linux template # KDE directory preferences .directory # Linux trash folder which might appear on any partition or disk .Trash-* ### Eclipse template *.pydevproject .metadata .gradlex *.bak *.swp *~.nib local.properties .settings/ .loadpath # Eclipse Core .project # External tool builders .externalToolBuilders/ # Locally stored "Eclipse launch configurations" *.launch # CDT-specific .cproject # JDT-specific (Eclipse Java Development Tools) .classpath # Java annotation processor (APT) .factorypath # PDT-specific .buildpath # sbteclipse plugin .target # TeXlipse plugin .texlipse ### OSX template .DS_Store .AppleDouble .LSOverride # Icon must end with two \r Icon # Thumbnails ._* # Files that might appear in the root of a volume .DocumentRevisions-V100 .fseventsd .Spotlight-V100 .TemporaryItems .Trashes .VolumeIcon.icns # Directories potentially created on remote AFP share .AppleDB .AppleDesktop Network Trash Folder Temporary Items .apdisk db.development.sqlite db.test.sqlite raw*.json # bower bower_components # distribution lib bundles # sessions sessions # logs *.log ================================================ FILE: LICENSE ================================================ The MIT License (MIT) Reactathon Copyright (c) 2016 Matt McFarland Some code heavily borrowed from hackathon-started by Sahat Yalkabov. https://github.com/sahat/hackathon-starter Hackathon Starter Copyright (c) 2014-2016 Sahat Yalkabov MIT Licensed Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================ # DEPRECATED This project has been superceded by the much more up-to-date, user-friendly, [react-create-app](https://github.com/facebookincubator/create-react-app) - which is perfect for hackathons or kickstarting your next react app! --- ### Getting started **1. Clone the Repo:** ```sh git clone https://github.com/MattMcFarland/reactathon.git ``` **2. Install Dependencies:** ```sh cd reactathon npm install ``` **3. Edit App config:** Edit `server/src/app.config.js` to setup everything. **4. Seed database:** Optionally run the seeder to create dummy data. ```sh npm run seed ``` **5. Run the dev server:** ```sh npm run dev ``` **6. Deploy when ready:** Deploy options are further down the guide :) ### FAQs - **What bells and whistles does Reactathon include?** - React.js - Node.js - Express.js - Babel.js 6.3.x ES7 Stage 0 - GraphQL - Relay ready - Sequelize SQL ORM - sqlite3 database - PhantomJS SEO - Winston logging - Passport.js with oAuth2 support - SQL User database - Github - Facebook - Twitter - Google Plus - Deployment with the following suites: - PM2 - Microsoft Azure - Heroku - **What are the System Requirements?** Reactathon has been tested with: - Mac OSX or Linux - Node.js v5.3.0 - Further testing needed to source our requirements - **Are the warnings a concern?** During `npm install` you may see warnings about deprecated or global packages. These are expected, and will not cause a problem. Should they become a problem, the project will be updated as needed. - **Are any of the bundled packages experimental?** Reactathon currently uses babel stage zero, which is considered experimental. As such, it is recommended to sustain upgrading babel until reactathon is more stable. ### Changelog - 0.10.2 - Update readme - Update package.json - 0.10.1 - Add resolve dependency - 0.10.0 - Add nav items for articles - 0.9.0 - Add database seeder (Issue: #6) - Add article list view (Issue: #3) - Add article detail view (Issue #20) - 0.8.1 - Update readme - 0.8.0 - Add Password reset views - Add Password reset endpoint - Add mailgun emailer - Add server endpoint for reset/forgot - 0.7.0 - Add winston logger - 0.6.x - 0.6.2 - Fix issue #16 (Slow dev startup) - 0.6.1 - update ecosystem.json to have correct value for development env - 0.6.0 - add link/unlink social provider functionality to the dashboard view - 0.5.0 - add start of user dashboard - add edge cases for signup and logout - add oauth for github, google, twitter, and facebook. - fix critical issue with missing files causing npm install to fail. - 0.4.x - 0.4.1 - Fix relayJS - 0.4.0 - Add Github oauth2 flow - 0.3.0 - Added social media button styling - Added client auth login logic - 0.2.0 - added adobe illustrator file - 0.1.0 - Fixed critical issue with example env vars not loading - Improved watch script speed - Add Token to model - 0.0.0 -- start ### License The MIT License ### Acknowledgements The idea of this hackathon starter project is heavily inspired from [Hackathon Starter](https://github.com/sahat/hackathon-starter) that was created by Sahat Yalkabov in 2014 and is still very much in active development. ================================================ FILE: client/client-manifest.json ================================================ { "dependencies": { "alt": "0.17.9", "classnames": "^2.2.1", "highlight.js": "^9.0.0", "history": "^1.17.0", "moment": "^2.11.0", "react": "^0.14.3", "react-bootstrap": "^0.28.1", "react-dom": "^0.14.3", "react-input-autosize": "^0.6.6", "react-notification-system": "^0.2.6", "react-relay": "^0.6.1", "react-router": "^2.0.0-rc4", "react-router-relay": "^0.9.0", "react-select": "^0.9.1", "superagent": "^1.6.1", "validator": "^4.5.0" } } ================================================ FILE: client/gulpCompressionOptions.js ================================================ module.exports = { sequences: true, // join consecutive statemets with the “comma operator” properties: true, // optimize property access: a["foo"] → a.foo dead_code: true, // discard unreachable code drop_debugger: true, // discard “debugger” statements unsafe: true, // some unsafe optimizations (see below) conditionals: true, // optimize if-s and conditional expressions comparisons: true, // optimize comparisons evaluate: true, // evaluate constant expressions booleans: true, // optimize boolean expressions loops: true, // optimize loops unused: true, // drop unused variables/functions hoist_funs: true, // hoist function declarations hoist_vars: true, // hoist variable declarations if_return: true, // optimize if-s followed by return/continue join_vars: true, // join var declarations cascade: true, // try to cascade `right` into `left` in sequences side_effects: true, // drop side-effect-free statements warnings: true, // warn about potentially dangerous optimizations/code global_defs: {} // global definitions }; ================================================ FILE: client/src/Layout.js ================================================ import React from 'react'; import { Link } from 'react-router'; import { Navbar, Nav, MenuItem, Modal, Button, NavDropdown } from 'react-bootstrap'; import { SignupForm, LoginForm } from './components'; import { Logo } from './components/partials/Elements'; import { AppActions } from './actions/AppActions'; import { AppStore } from './stores/AppStore'; import NotificationSystem from 'react-notification-system'; const Content = ({children}) => (
{children}
); export class Layout extends React.Component { constructor() { super(); this.state = { ...AppStore.getState() }; this._notificationSystem = null; this.onChange = this.onChange.bind(this); } componentDidMount() { AppStore.listen(this.onChange); this._notificationSystem = this.refs.notificationSystem; } componentWillUnmount() { AppStore.unlisten(this.onChange); } addNotification = (queue) => { let message = queue.slice(0, 1); this._notificationSystem.addNotification(message[0]); }; onChange(state) { if (state.queue && state.queue.length) { setTimeout(this.addNotification(state.queue), 100); } this.setState(state); } render() { var Menu; var name = this.props.location.pathname; let { showSignupModal, showLoginModal } = this.state; let onShowSignupForm = () => (AppActions.showSignupModal()); let onShowLoginForm = () => (AppActions.showLoginModal()); let onHideSignupForm = () => (AppActions.hideSignupModal()); let onHideLoginForm = () => (AppActions.hideLoginModal()); let logout = (e) => { e.preventDefault(); AppActions.logout(); }; let gotoDashboard = (e) => { e.preventDefault(); this.props.history.push('/dashboard'); }; let gotoAddNewArticle = (e) => { e.preventDefault(); this.props.history.push('/add-article'); }; if (this.state.user) { Menu = ({}) => ( ); } else { Menu = ({}) => ( ); } return (
{this.props.children}
{showSignupModal ? Signup : ''} {showLoginModal ? Login : ''}
); } } Layout.contextTypes = { router: React.PropTypes.object.isRequired }; ================================================ FILE: client/src/__tests__/ok.js ================================================ ================================================ FILE: client/src/actions/AppActions.js ================================================ import alt from '../alt'; import ajax from 'superagent'; class AppActionsSpec { constructor() { this.generateActions( 'signupPending', 'signupSuccess', 'signupFail', 'loginPending', 'loginSuccess', 'loginFail', 'logoutPending', 'logoutSuccess', 'logoutFail', 'addArticlePending', 'addArticleSuccess', 'addArticleFail', 'requestNewPassword', 'showSignupModal', 'hideSignupModal', 'showLoginModal', 'hideLoginModal', 'pushQueue', 'shiftQueue' ); } logout() { ajax.post('/api/logout') .end((err, res) => { if (!err) { if (res && res.body) { this.actions.pushQueue({ level: 'success', title: 'Goodbye!', message: 'You are now logged out!' }); this.actions.shiftQueue(); this.actions.logoutFail(); this.actions.logoutSuccess(res.body.user); } else { this.actions.pushQueue({ level: 'error', title: 'Oh snap!', message: 'Something bad happened!' }); this.actions.shiftQueue(); this.actions.logoutFail(); } } else { this.actions.logoutFail(err); } }); this.actions.logoutPending(); } login({username, password}) { ajax.post('/api/login') .send({ username, password }) .set('Content-Type', 'application/json') .set('Accept', 'application/json') .end((err, res) => { if (!err) { if (res && res.body && res.body.user) { this.actions.pushQueue({ level: 'success', title: 'Success!', message: 'You are now logged in!' }); this.actions.shiftQueue(); this.actions.loginFail(); this.actions.loginSuccess(res.body.user); } else { this.actions.pushQueue({ level: 'error', title: 'Oh snap!', message: 'Something bad happened!' }); this.actions.shiftQueue(); this.actions.loginFail(); } } else { this.actions.loginFail(err); } }); this.actions.loginPending(); } addArticle({title, content}) { ajax.post('/api/add-article') .send({ title, content }) .set('Content-Type', 'application/json') .set('Accept', 'application/json') .end((err, res) => { if (!err) { if (res && res.body && res.body.user) { this.actions.pushQueue({ level: 'success', title: 'Success!', message: 'Your article has been created!' }); this.actions.shiftQueue(); this.actions.addArticleFail(); this.actions.addArticleSuccess(res.body.user); } else { this.actions.pushQueue({ level: 'error', title: 'Oh snap!', message: 'Something bad happened!' }); this.actions.shiftQueue(); this.actions.addArticleFail(); } } else { this.actions.addArticleFail(err); } }); this.actions.addArticlePending(); } signup({username, password, email}) { ajax.post('/api/signup') .send({ username, password, email }) .set('Content-Type', 'application/json') .set('Accept', 'application/json') .end((err, res) => { if (!err) { if (res && res.body && res.body.user) { this.actions.pushQueue({ level: 'success', title: 'Success!', message: 'You are now logged in!' }); this.actions.shiftQueue(); this.actions.signupFail(); this.actions.signupSuccess(res.body.user); } else { this.actions.pushQueue({ level: 'error', title: 'Oh snap!', message: 'Something bad happened!' }); this.actions.shiftQueue(); this.actions.signupFail(); } } else { this.actions.signupFail(err); } }); this.actions.signupPending(); } toast(options) { this.actions.pushQueue(options); this.actions.shiftQueue(); } } export const AppActions = alt.createActions(AppActionsSpec); ================================================ FILE: client/src/alt.js ================================================ import Alt from 'alt'; var alt = new Alt(); export default alt; ================================================ FILE: client/src/components/AddNewArticleForm.js ================================================ import React from 'react'; import { FormErrors } from './partials'; import { Button, Input, ButtonInput } from 'react-bootstrap'; import { AppActions } from '../actions/AppActions'; import { AppStore } from '../stores/AppStore'; export class AddNewArticleForm extends React.Component { constructor() { super(); this.state = { ...AppStore.getState(), title: '', content: '' }; this.onChange = this.onChange.bind(this); } componentDidMount() { AppStore.listen(this.onChange); } componentWillUnmount() { AppStore.unlisten(this.onChange); } onChange(state) { this.setState(state); } handleTitleChange = (e => this.onChange( {title: e.target.value}) ); handleContentChange = (e => this.onChange( {content: e.target.value}) ); validate = () => { var errors = []; var { title, content } = this.state; const rules = [ { failOn: title.trim().length < 10, error: 'Title must be at least 10 characters' }, { failOn: content.trim().length < 30, error: 'Content must be at least 30 characters' } ]; rules.forEach((rule) => { if (rule.failOn) { errors.push(rule); } }); if (errors.length) { return { errors: errors, valid: false }; } else { return { errors: null, valid: true }; } }; handleSubmit = (e) => { e.preventDefault(); var valid = this.validate(); if (valid.errors) { let article = valid.errors.length > 1 ? 'are' : 'is'; let noun = valid.errors.length > 1 ? 'errors' : 'error'; let count = valid.errors.length > 1 ? valid.errors.length : 'one'; this.setState({ error: { message: `There ${article} ${count} ${noun}, please try again.`, data: valid.errors } }); return; } AppActions.addArticle({ title: this.state.title, content: this.state.content }); }; render() { // handlers let { handleSubmit, handleTitleChange, handleContentChange } = this; // state let { error, title, content } = this.state; return (
{error ? : ''}

Create new Article


{this.state.addArticlePending ? : }
); } } ================================================ FILE: client/src/components/LoginForm.js ================================================ import React from 'react'; import { Link } from 'react-router'; import { FormErrors } from './partials'; import { Center, LoginWith } from './partials/Elements'; import { Button, Input, ButtonInput } from 'react-bootstrap'; import { AppActions } from '../actions/AppActions'; import { AppStore } from '../stores/AppStore'; export class LoginForm extends React.Component { constructor() { super(); this.state = { ...AppStore.getState(), username: '', password: '' }; this.onChange = this.onChange.bind(this); } componentDidMount() { AppStore.listen(this.onChange); } componentWillUnmount() { AppStore.unlisten(this.onChange); } onChange(state) { this.setState(state); } clearState = () => { this.setState({ username: '', password: '' }); }; handleForgotPasswordClick = () => { AppActions.hideLoginModal(); }; handleUsernameChange = (e => this.onChange( {username: e.target.value}) ); handlePasswordChange = (e => this.onChange( {password: e.target.value}) ); validate = () => { var errors = []; var { username, password } = this.state; const rules = [ { failOn: username.trim().length < 4, error: 'Username must be at least 4 characters' }, { failOn: password.trim().length < 5, error: 'Password must be at least 5 characters' } ]; rules.forEach((rule) => { if (rule.failOn) { errors.push(rule); } }); if (errors.length) { return { errors: errors, valid: false }; } else { return { errors: null, valid: true }; } }; handleSubmit = (e) => { e.preventDefault(); var valid = this.validate(); if (valid.errors) { let article = valid.errors.length > 1 ? 'are' : 'is'; let noun = valid.errors.length > 1 ? 'errors' : 'error'; let count = valid.errors.length > 1 ? valid.errors.length : 'one'; this.setState({ error: { message: `There ${article} ${count} ${noun}, please try again.`, data: valid.errors } }); return; } AppActions.login({ username: this.state.username, password: this.state.password }); }; render() { // handlers let { handleSubmit, handleUsernameChange, handlePasswordChange, handleForgotPasswordClick } = this; // state let { error, username, password } = this.state; return (
{error ? : ''}

Login with social account


Sign in with local account


{this.state.signupPending ? : } Forgot your password?
); } } ================================================ FILE: client/src/components/ResetPasswordForm.js ================================================ import React from 'react'; import ajax from 'superagent'; import { Link } from 'react-router'; import { FormErrors } from './partials'; import { AppActions } from '../actions/AppActions'; import { Input, ButtonInput } from 'react-bootstrap'; export class ResetPasswordForm extends React.Component { constructor() { super(); this.state = { newPassword: '', processing: false, passwordReset: false, errors: [] }; } handleInputChange = (e => this.setState( {newPassword: e.target.value}) ); validate = () => { var errors = []; var { newPassword } = this.state; const rules = [ { failOn: newPassword.trim().length < 5, error: 'Password must be at least 5 characters' } ]; rules.forEach((rule) => { if (rule.failOn) { errors.push(rule); } }); if (errors.length) { return { errors: errors, valid: false }; } else { return { errors: null, valid: true }; } }; handleSubmit = (e) => { let newPassword = this.state.newPassword; e.preventDefault(); var valid = this.validate(); if (valid.errors) { let article = valid.errors.length > 1 ? 'are' : 'is'; let noun = valid.errors.length > 1 ? 'errors' : 'error'; let count = valid.errors.length > 1 ? valid.errors.length : 'one'; this.setState({ error: { processing: false, message: `There ${article} ${count} ${noun}, please try again.`, data: valid.errors } }); return; } this.setState({ processing: true }); ajax.post('/api/reset') .send({password: newPassword}) .end((err, res) => { if (err || res.text !== 'ok') { AppActions.toast({ level: 'error', title: 'Server Error', message: 'Password reset token is invalid or has expired.' }); this.context.router.push('/reset'); } AppActions.toast({ level: 'success', title: 'Success', message: 'Your password has been changed.' }); this.setState({ passwordReset: true }); }); }; render() { let { processing, passwordReset, error, newPassword } = this.state; if (passwordReset) { return (

Password successfully reset.

Go Login

); } else { return (
{error ? : ''}
Reset Password

Enter a new password:

Change Password
); } } } ResetPasswordForm.contextTypes = { router: React.PropTypes.object.isRequired }; ================================================ FILE: client/src/components/ResetRequestForm.js ================================================ import React from 'react'; import ajax from 'superagent'; import { Link } from 'react-router'; import { Input, ButtonInput } from 'react-bootstrap'; export class ResetRequestForm extends React.Component { constructor() { super(); this.state = { pending: false, email: '', emailSent: false, }; } handleInputChange = (e => this.setState( {email: e.target.value}) ); handleSubmit = (e) => { let email = this.state.email; e.preventDefault(); this.setState({ pending: true }); if (this.state.emailSent) { return; } ajax.post('/api/forgot') .send({email}) .end((err, res) => { this.setState({ emailSent: true }); console.info(err, res); }); }; render() { let { emailSent, email, pending } = this.state; if (emailSent) { return (

A link to reset your password has been sent to  {email}. Make sure to check your spam folder in case you do not see it.

Back to home

); } else { return (
Reset Password

Enter your email address below and  we will send you a link to reset your password

Send reset link
); } } } ================================================ FILE: client/src/components/SignupForm.js ================================================ import React from 'react'; import validator from 'validator'; import { FormErrors } from './partials'; import { Button, Input, ButtonInput } from 'react-bootstrap'; import { AppActions } from '../actions/AppActions'; import { AppStore } from '../stores/AppStore'; export class SignupForm extends React.Component { constructor() { super(); this.state = { ...AppStore.getState(), username: '', password: '', email: '' }; this.onChange = this.onChange.bind(this); } componentDidMount() { AppStore.listen(this.onChange); } componentWillUnmount() { AppStore.unlisten(this.onChange); } onChange(state) { this.setState(state); } clearState = () => { this.setState({ username: '', password: '', email: '' }); }; handleUsernameChange = (e => this.onChange( {username: e.target.value}) ); handlePasswordChange = (e => this.onChange( {password: e.target.value}) ); handleEmailChange = (e => this.onChange( {email: e.target.value}) ); validate = () => { var errors = []; var { username, password, email } = this.state; const rules = [ { failOn: !validator.isEmail(email), error: 'Please use a valid email address' }, { failOn: username.trim().length < 4, error: 'Username must be at least 4 characters' }, { failOn: password.trim().length < 5, error: 'Password must be at least 5 characters' } ]; rules.forEach((rule) => { if (rule.failOn) { errors.push(rule); } }); if (errors.length) { return { errors: errors, valid: false }; } else { return { errors: null, valid: true }; } }; handleSubmit = (e) => { e.preventDefault(); var valid = this.validate(); if (valid.errors) { let article = valid.errors.length > 1 ? 'are' : 'is'; let noun = valid.errors.length > 1 ? 'errors' : 'error'; let count = valid.errors.length > 1 ? valid.errors.length : 'one'; this.setState({ error: { message: `There ${article} ${count} ${noun}, please try again.`, data: valid.errors } }); return; } AppActions.signup({ username: this.state.username, password: this.state.password, email: this.state.email }); }; render() { // handlers let { handleSubmit, handleUsernameChange, handlePasswordChange, handleEmailChange } = this; // state let { error, username, password, email } = this.state; return (
{error ? : ''}

Create an Account


{this.state.signupPending ? : }
); } } ================================================ FILE: client/src/components/index.js ================================================ export { LoginForm } from './LoginForm'; export { SignupForm } from './SignupForm'; export { ResetRequestForm } from './ResetRequestForm'; export { ResetPasswordForm } from './ResetPasswordForm'; export { AddNewArticleForm } from './AddNewArticleForm'; ================================================ FILE: client/src/components/partials/Elements.js ================================================ import React from 'react'; import { Collapse, Button } from 'react-bootstrap'; const performRedirect = (path) => ( window.location.href = path ); const val = (prop) => ( Object.keys(prop).join(' ') ); const redirect = { github: () => performRedirect('/auth/github'), reddit: () => performRedirect('/auth/reddit'), twitter: () => performRedirect('/auth/twitter'), facebook: () => performRedirect('/auth/facebook'), google: () => performRedirect('/auth/google') }; export const LeftIconButton = (props) => ( ); export const LoginWith = (account) => (
 Sign in with {val(account)}
); export const LeftFa = (icon) => ( ); export const Fa = (icon) => ( ); export const Logo = ({ size = 'auto' }) => ( React athon ); export const Center = ({ children }) => (
{children}
); export const Icon = ({ name }) => ( ); export const Alert = ({ children, kind = 'info' }) => (
{children}
); const selectAll = (e) => { let target = e.target; target.setSelectionRange(0, target.value.length); }; export const PastaLink = ({ label, value }) => (
); const Title = ({ children }) => ( {children} ); export const Radio = ({ name, value, children, onChange, set }) => ( ); export const Expander = ({ isExpanded = false, title, children, onToggle }) => ( <Button kind="link btn-sm" onClick={onToggle}> {title}   <Icon name={isExpanded ? 'caret-down' : 'caret-right'}/> </Button>
{children}
); ================================================ FILE: client/src/components/partials/FormErrors.js ================================================ import React from 'react'; import { Alert } from './Elements'; const ErrorItem = ({msg}) => (
{msg}
); export const FormErrors = ({ message, data }) => ( {message} {data.map((item, i) => )} ); ================================================ FILE: client/src/components/partials/index.js ================================================ export { FormErrors } from './FormErrors'; export { Elements } from './Elements'; ================================================ FILE: client/src/containers/AddNewArticle.js ================================================ import React from 'react'; import { AddNewArticleForm } from '../components'; export const AddNewArticle = () => (
); ================================================ FILE: client/src/containers/Article.js ================================================ import React from 'react'; import Relay from 'react-relay'; import moment from 'moment'; class ArticleComponent extends React.Component { render() { var { author, title, content, dateCreated } = this.props.article; console.log(this.props); return (

{title}

by {author.username} - {moment(dateCreated).fromNow()}.

{content}

); } } export const Article = Relay.createContainer(ArticleComponent, { fragments: { article: () => Relay.QL` fragment on Article { author { username } title content dateCreated } ` } }); ================================================ FILE: client/src/containers/ArticleList.js ================================================ import React from 'react'; import Relay from 'react-relay'; import { Link } from 'react-router'; import moment from 'moment'; const ArticleListItem = ({ author, dateCreated, title, content, url }) => (
{author.username} posted an article {moment(dateCreated).fromNow()}.
{title}

{content}

); class ArticleListComponent extends React.Component { renderList = () => { return this.props.viewer.articles.edges.map(edge => ); }; loadNextPage = () => { // Increments the number of articles being rendered by 5. this.props.relay.setVariables({ count: this.props.relay.variables.count + 5 }); }; render() { var hasNextPage = this.props.viewer.articles.pageInfo.hasNextPage; return (
{this.renderList()}
{hasNextPage ? : ''}
); } } export const ArticleList = Relay.createContainer(ArticleListComponent, { initialVariables: { count: 5 }, fragments: { viewer: () => Relay.QL` fragment on GraphAPI { articles(first: $count) { pageInfo { hasNextPage } edges { node { id url author { username } dateCreated content title } } } } ` } }); ================================================ FILE: client/src/containers/Dashboard.js ================================================ import React from 'react'; import Relay from 'react-relay'; import moment from 'moment'; import { Col, Row, // Panel, Button, Input, Thumbnail, ButtonInput } from 'react-bootstrap'; const UserCard = ({ displayName, location, pictureUrl, username, website, dateCreated }) => (

Hello, {displayName}!

Joined {moment(dateCreated).fromNow()}

{username ? username : ''}

{location}

{website}

); class DashboardComponent extends React.Component { constructor(props) { console.log(props); super(props); } onLinkFacebook = () => (window.location.href = '/auth/facebook'); onLinkGithub = () => (window.location.href = '/auth/github'); onLinkReddit = () => (window.location.href = '/auth/reddit'); onLinkGoogle = () => (window.location.href = '/auth/google'); onLinkTwitter = () => (window.location.href = '/auth/twitter'); onUnlinkFacebook = () => (window.location.href = '/auth/unlink/facebook'); onUnlinkGithub = () => (window.location.href = '/auth/unlink/github'); onUnlinkReddit = () => (window.location.href = '/auth/unlink/reddit'); onUnlinkGoogle = () => (window.location.href = '/auth/unlink/google'); onUnlinkTwitter = () => (window.location.href = '/auth/unlink/twitter'); render() { // Store let { website, email, username, github, google, twitter, facebook, reddit } = this.props.viewer.user; return (
Providers {facebook ? 'Unlink' : 'link'} {reddit ? 'Unlink' : 'link'} {github ? 'Unlink' : 'link'} {google ? 'Unlink' : 'link'} {twitter ? 'Unlink' : 'link'}
); } } export const Dashboard = Relay.createContainer(DashboardComponent, { initialVariables: { id: localStorage.getItem('user') }, fragments: { viewer: () => Relay.QL` fragment on GraphAPI { user(id: $id) { displayName, dateCreated, username, email, location, website, pictureUrl, github google twitter facebook reddit } } ` } }); ================================================ FILE: client/src/containers/Home.js ================================================ import React from 'react'; import { Logo, Center } from '../components/partials/Elements'; export const Home = () => (


); ================================================ FILE: client/src/containers/Login.js ================================================ import React from 'react'; import { LoginForm } from '../components'; export const Login = () => (
); ================================================ FILE: client/src/containers/NoMatch.js ================================================ import React from 'react'; export const NoMatch = () => (

Not Found

Sorry, the page requested was not found

); ================================================ FILE: client/src/containers/Page.js ================================================ import React from 'react'; import ajax from 'superagent'; import marked from 'marked'; export class Page extends React.Component { constructor(props) { super(props); this.state = {}; ajax.get('/api/page/' + props.params.id, (err, res) => { if (err || !res) { this.setState({errorPage: true}); } else { try { let data = marked(res.text.toString(), {sanitize: true}); this.setState({ data }); } catch (e) { this.setState({errorPage: true}); } } }); } render() { if (this.state.errorPage) { return (

Not Found

Sorry, the page requested was not found

); } else { return (
); } } } ================================================ FILE: client/src/containers/ResetPassword.js ================================================ import React from 'react'; import { ResetPasswordForm } from '../components'; export const ResetPassword = () => (
); ================================================ FILE: client/src/containers/ResetRequest.js ================================================ import React from 'react'; import { ResetRequestForm } from '../components'; export const ResetRequest = () => (
); ================================================ FILE: client/src/containers/SignUp.js ================================================ import React from 'react'; import { SignupForm } from '../components'; export const SignUp = () => (
); ================================================ FILE: client/src/containers/Tag.js ================================================ import React from 'react'; export const Tag = () => (

TODO: Update me

); ================================================ FILE: client/src/containers/TagList.js ================================================ import React from 'react'; export const TagList = () => (

TODO: Update me

); ================================================ FILE: client/src/containers/User.js ================================================ import React from 'react'; import Relay from 'react-relay'; import { Col, Row } from 'react-bootstrap'; const ProfilePicture = () => (
ProfilePicture Here
); const UserLocation = () => (
UserLocation Here
); const UserWebsite = () => (
UserWebsite Here
); class UserComponent extends React.Component { constructor(props) { console.log(props); super(props); } render() { return (
); } } export const User = Relay.createContainer(UserComponent, { fragments: { user: () => Relay.QL` fragment on User { username, displayName } ` } }); ================================================ FILE: client/src/containers/index.js ================================================ export { Home } from './Home'; export { Article } from './Article'; export { ArticleList } from './ArticleList'; export { Page } from './Page'; export { TagList } from './TagList'; export { NoMatch } from './NoMatch'; export { Tag } from './Tag'; export { Login } from './Login'; export { SignUp } from './SignUp'; export { Dashboard } from './Dashboard'; export { User } from './User'; export { ResetRequest } from './ResetRequest'; export { ResetPassword } from './ResetPassword'; export { AddNewArticle } from './AddNewArticle'; ================================================ FILE: client/src/main.js ================================================ /* * React */ import React from 'react'; import { render } from 'react-dom'; /* * React-Router */ import { browserHistory, IndexRoute, Route } from 'react-router'; /* * Relay */ import Relay from 'react-relay'; import { RelayRouter } from 'react-router-relay'; /* * Layout */ import { Layout } from './Layout'; /* * Containers */ import { Article, ArticleList, Home, NoMatch, Page, Login, SignUp, Tag, TagList, Dashboard, User, ResetRequest, ResetPassword, AddNewArticle } from './containers'; const viewerQuery = { viewer: () => Relay.QL`query { viewer }` }; const articleQuery = { article: () => Relay.QL` query { article(id: $articleId) } ` }; class Master extends React.Component { render() { return ( Relay.QL`query { user(id: $id) }` }} /> Relay.QL`query { viewer }` }} component={Dashboard}/> ); } } Master.contextTypes = { router: React.PropTypes.string }; render(( ), document.getElementById('main')); ================================================ FILE: client/src/queries/ViewerQueries.js ================================================ import Relay from 'react-relay'; export default { viewer: () => Relay.QL`query { viewer }` }; ================================================ FILE: client/src/queries/index.js ================================================ export { ViewerQueries } from './ViewerQueries'; ================================================ FILE: client/src/stores/AppStore.js ================================================ import alt from '../alt'; import { AppActions } from '../actions/AppActions'; class AppStoreSpec { constructor() { this.bindActions(AppActions); var userEl = document.getElementById('user'); this.user = userEl ? JSON.parse(userEl.innerHTML) : null; localStorage.setItem('user', this.user); this.showSignupModal = false; this.showLoginModal = false; this.signupPending = false; this.queue = []; } onShowSignupModal() { this.setState({showSignupModal: true}); } onHideSignupModal() { this.setState({showSignupModal: false}); } onShowLoginModal() { this.setState({showLoginModal: true}); } onHideLoginModal() { this.setState({showLoginModal: false}); } onSignupPending = () => { localStorage.removeItem('user'); this.signupPending = true; }; onSignupSuccess(user) { this.user = user.id.toString(); localStorage.setItem('user', this.user); this.signupPending = false; this.showSignupModal = false; window.location.href = '/dashboard'; } onSignupFail() { this.signupPending = false; localStorage.removeItem('user'); } onLoginPending = () => { localStorage.removeItem('user'); this.loginPending = true; }; onLoginSuccess(user) { this.user = user.id.toString(); localStorage.setItem('user', this.user); this.loginPending = false; this.showLoginModal = false; } onLoginFail() { this.loginPending = false; localStorage.removeItem('user'); } onAddArticleSuccess() { this.addArticlePending = false; } onAddArticleFail() { this.addArticlePending = false; } onLogoutPending = () => (this.logoutPending = true); onLogoutSuccess() { this.user = null; localStorage.removeItem('user'); this.logoutPending = false; window.location.href = '/'; } onLogoutFail() { this.logoutPending = false; } onPushQueue(options) { this.queue.push(options); } onShiftQueue() { this.queue.shift(); } } export const AppStore = alt.createStore(AppStoreSpec, 'AppStore'); ================================================ FILE: client/src/style/base/_transitions.scss ================================================ $page-trans-time: 0.3s; $page-trans-easing: ease-in-out; .page-transition { &-enter, &-leave { transition: opacity $page-trans-time $page-trans-easing; position: absolute; } &-enter { opacity: 0; &-active { opacity: 1; } } &-leave { opacity: 1; &-active { opacity: 0; } } } ================================================ FILE: client/src/style/base/_variables.scss ================================================ $twitterBlue: #00aced; $facebookBlue: #335795; $googleRed: #DD4B39; $redditBlue: #99BEEB; $githubBlack: #333; $page-trans-time: 0.1s; $page-trans-easing: ease-in-out; ================================================ FILE: client/src/style/main.scss ================================================ @import './vendor/bootstrap'; @import './base/variables'; @import './base/transitions'; @import './objects/buttons'; ================================================ FILE: client/src/style/objects/_buttons.scss ================================================ .btn .fa.fix-left { float: left; height: 1em; font-size: 26px; border-right: thin ridge rgba(255, 255, 255, 0.3); width: 45px; margin-left: -15px; margin-right: -45px; &:after { border-right: thin solid white; } } .social-btn { font-size: 18px; color: white; &:hover, &:focus, &:active { color: white; } &-github { background-color: $githubBlack; &:hover, &:focus, &:active { background-color: lighten($githubBlack, 10%); } } &-google { background-color: $googleRed; &:hover, &:focus, &:active { background-color: lighten($googleRed, 10%); } } &-reddit { background-color: $redditBlue; color: black; &:hover, &:focus, &:active { background-color: lighten($redditBlue, 10%); color: black; } } &-twitter { background-color: $twitterBlue; &:hover, &:focus, &:active { background-color: lighten($twitterBlue, 10%); } } &-facebook { background-color: $facebookBlue; &:hover, &:focus, &:active { background-color: lighten($facebookBlue, 10%); } } } ================================================ FILE: client/src/style/vendor/_bootstrap.scss ================================================ /*! * Bootstrap v3.3.6 (http://getbootstrap.com) * Copyright 2011-2015 Twitter, Inc. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) */ // Core variables and mixins @import "bootstrap/variables"; @import "bootstrap/mixins"; // Reset and dependencies @import "bootstrap/normalize"; @import "bootstrap/print"; @import "bootstrap/glyphicons"; // Core CSS @import "bootstrap/scaffolding"; @import "bootstrap/type"; @import "bootstrap/code"; @import "bootstrap/grid"; @import "bootstrap/tables"; @import "bootstrap/forms"; @import "bootstrap/buttons"; // Components @import "bootstrap/component-animations"; @import "bootstrap/dropdowns"; @import "bootstrap/button-groups"; @import "bootstrap/input-groups"; @import "bootstrap/navs"; @import "bootstrap/navbar"; @import "bootstrap/breadcrumbs"; @import "bootstrap/pagination"; @import "bootstrap/pager"; @import "bootstrap/labels"; @import "bootstrap/badges"; @import "bootstrap/jumbotron"; @import "bootstrap/thumbnails"; @import "bootstrap/alerts"; @import "bootstrap/progress-bars"; @import "bootstrap/media"; @import "bootstrap/list-group"; @import "bootstrap/panels"; @import "bootstrap/responsive-embed"; @import "bootstrap/wells"; @import "bootstrap/close"; // Components w/ JavaScript @import "bootstrap/modals"; @import "bootstrap/tooltip"; @import "bootstrap/popovers"; @import "bootstrap/carousel"; // Utility classes @import "bootstrap/utilities"; @import "bootstrap/responsive-utilities"; ================================================ FILE: client/src/style/vendor/bootstrap/_alerts.scss ================================================ // // Alerts // -------------------------------------------------- // Base styles // ------------------------- .alert { padding: $alert-padding; margin-bottom: $line-height-computed; border: 1px solid transparent; border-radius: $alert-border-radius; // Headings for larger alerts h4 { margin-top: 0; // Specified for the h4 to prevent conflicts of changing $headings-color color: inherit; } // Provide class for links that match alerts .alert-link { font-weight: $alert-link-font-weight; } // Improve alignment and spacing of inner content > p, > ul { margin-bottom: 0; } > p + p { margin-top: 5px; } } // Dismissible alerts // // Expand the right padding and account for the close button's positioning. .alert-dismissable, // The misspelled .alert-dismissable was deprecated in 3.2.0. .alert-dismissible { padding-right: ($alert-padding + 20); // Adjust close link position .close { position: relative; top: -2px; right: -21px; color: inherit; } } // Alternate styles // // Generate contextual modifier classes for colorizing the alert. .alert-success { @include alert-variant($alert-success-bg, $alert-success-border, $alert-success-text); } .alert-info { @include alert-variant($alert-info-bg, $alert-info-border, $alert-info-text); } .alert-warning { @include alert-variant($alert-warning-bg, $alert-warning-border, $alert-warning-text); } .alert-danger { @include alert-variant($alert-danger-bg, $alert-danger-border, $alert-danger-text); } ================================================ FILE: client/src/style/vendor/bootstrap/_badges.scss ================================================ // // Badges // -------------------------------------------------- // Base class .badge { display: inline-block; min-width: 10px; padding: 3px 7px; font-size: $font-size-small; font-weight: $badge-font-weight; color: $badge-color; line-height: $badge-line-height; vertical-align: middle; white-space: nowrap; text-align: center; background-color: $badge-bg; border-radius: $badge-border-radius; // Empty badges collapse automatically (not available in IE8) &:empty { display: none; } // Quick fix for badges in buttons .btn & { position: relative; top: -1px; } .btn-xs &, .btn-group-xs > .btn & { top: 0; padding: 1px 5px; } // [converter] extracted a& to a.badge // Account for badges in navs .list-group-item.active > &, .nav-pills > .active > a > & { color: $badge-active-color; background-color: $badge-active-bg; } .list-group-item > & { float: right; } .list-group-item > & + & { margin-right: 5px; } .nav-pills > li > a > & { margin-left: 3px; } } // Hover state, but only for links a.badge { &:hover, &:focus { color: $badge-link-hover-color; text-decoration: none; cursor: pointer; } } ================================================ FILE: client/src/style/vendor/bootstrap/_breadcrumbs.scss ================================================ // // Breadcrumbs // -------------------------------------------------- .breadcrumb { padding: $breadcrumb-padding-vertical $breadcrumb-padding-horizontal; margin-bottom: $line-height-computed; list-style: none; background-color: $breadcrumb-bg; border-radius: $border-radius-base; > li { display: inline-block; + li:before { // [converter] Workaround for https://github.com/sass/libsass/issues/1115 $nbsp: "\00a0"; content: "#{$breadcrumb-separator}#{$nbsp}"; // Unicode space added since inline-block means non-collapsing white-space padding: 0 5px; color: $breadcrumb-color; } } > .active { color: $breadcrumb-active-color; } } ================================================ FILE: client/src/style/vendor/bootstrap/_button-groups.scss ================================================ // // Button groups // -------------------------------------------------- // Make the div behave like a button .btn-group, .btn-group-vertical { position: relative; display: inline-block; vertical-align: middle; // match .btn alignment given font-size hack above > .btn { position: relative; float: left; // Bring the "active" button to the front &:hover, &:focus, &:active, &.active { z-index: 2; } } } // Prevent double borders when buttons are next to each other .btn-group { .btn + .btn, .btn + .btn-group, .btn-group + .btn, .btn-group + .btn-group { margin-left: -1px; } } // Optional: Group multiple button groups together for a toolbar .btn-toolbar { margin-left: -5px; // Offset the first child's margin @include clearfix; .btn, .btn-group, .input-group { float: left; } > .btn, > .btn-group, > .input-group { margin-left: 5px; } } .btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) { border-radius: 0; } // Set corners individual because sometimes a single button can be in a .btn-group and we need :first-child and :last-child to both match .btn-group > .btn:first-child { margin-left: 0; &:not(:last-child):not(.dropdown-toggle) { @include border-right-radius(0); } } // Need .dropdown-toggle since :last-child doesn't apply given a .dropdown-menu immediately after it .btn-group > .btn:last-child:not(:first-child), .btn-group > .dropdown-toggle:not(:first-child) { @include border-left-radius(0); } // Custom edits for including btn-groups within btn-groups (useful for including dropdown buttons within a btn-group) .btn-group > .btn-group { float: left; } .btn-group > .btn-group:not(:first-child):not(:last-child) > .btn { border-radius: 0; } .btn-group > .btn-group:first-child:not(:last-child) { > .btn:last-child, > .dropdown-toggle { @include border-right-radius(0); } } .btn-group > .btn-group:last-child:not(:first-child) > .btn:first-child { @include border-left-radius(0); } // On active and open, don't show outline .btn-group .dropdown-toggle:active, .btn-group.open .dropdown-toggle { outline: 0; } // Sizing // // Remix the default button sizing classes into new ones for easier manipulation. .btn-group-xs > .btn { @extend .btn-xs; } .btn-group-sm > .btn { @extend .btn-sm; } .btn-group-lg > .btn { @extend .btn-lg; } // Split button dropdowns // ---------------------- // Give the line between buttons some depth .btn-group > .btn + .dropdown-toggle { padding-left: 8px; padding-right: 8px; } .btn-group > .btn-lg + .dropdown-toggle { padding-left: 12px; padding-right: 12px; } // The clickable button for toggling the menu // Remove the gradient and set the same inset shadow as the :active state .btn-group.open .dropdown-toggle { @include box-shadow(inset 0 3px 5px rgba(0,0,0,.125)); // Show no shadow for `.btn-link` since it has no other button styles. &.btn-link { @include box-shadow(none); } } // Reposition the caret .btn .caret { margin-left: 0; } // Carets in other button sizes .btn-lg .caret { border-width: $caret-width-large $caret-width-large 0; border-bottom-width: 0; } // Upside down carets for .dropup .dropup .btn-lg .caret { border-width: 0 $caret-width-large $caret-width-large; } // Vertical button groups // ---------------------- .btn-group-vertical { > .btn, > .btn-group, > .btn-group > .btn { display: block; float: none; width: 100%; max-width: 100%; } // Clear floats so dropdown menus can be properly placed > .btn-group { @include clearfix; > .btn { float: none; } } > .btn + .btn, > .btn + .btn-group, > .btn-group + .btn, > .btn-group + .btn-group { margin-top: -1px; margin-left: 0; } } .btn-group-vertical > .btn { &:not(:first-child):not(:last-child) { border-radius: 0; } &:first-child:not(:last-child) { @include border-top-radius($btn-border-radius-base); @include border-bottom-radius(0); } &:last-child:not(:first-child) { @include border-top-radius(0); @include border-bottom-radius($btn-border-radius-base); } } .btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn { border-radius: 0; } .btn-group-vertical > .btn-group:first-child:not(:last-child) { > .btn:last-child, > .dropdown-toggle { @include border-bottom-radius(0); } } .btn-group-vertical > .btn-group:last-child:not(:first-child) > .btn:first-child { @include border-top-radius(0); } // Justified button groups // ---------------------- .btn-group-justified { display: table; width: 100%; table-layout: fixed; border-collapse: separate; > .btn, > .btn-group { float: none; display: table-cell; width: 1%; } > .btn-group .btn { width: 100%; } > .btn-group .dropdown-menu { left: auto; } } // Checkbox and radio options // // In order to support the browser's form validation feedback, powered by the // `required` attribute, we have to "hide" the inputs via `clip`. We cannot use // `display: none;` or `visibility: hidden;` as that also hides the popover. // Simply visually hiding the inputs via `opacity` would leave them clickable in // certain cases which is prevented by using `clip` and `pointer-events`. // This way, we ensure a DOM element is visible to position the popover from. // // See https://github.com/twbs/bootstrap/pull/12794 and // https://github.com/twbs/bootstrap/pull/14559 for more information. [data-toggle="buttons"] { > .btn, > .btn-group > .btn { input[type="radio"], input[type="checkbox"] { position: absolute; clip: rect(0,0,0,0); pointer-events: none; } } } ================================================ FILE: client/src/style/vendor/bootstrap/_buttons.scss ================================================ // // Buttons // -------------------------------------------------- // Base styles // -------------------------------------------------- .btn { display: inline-block; margin-bottom: 0; // For input.btn font-weight: $btn-font-weight; text-align: center; vertical-align: middle; touch-action: manipulation; cursor: pointer; background-image: none; // Reset unusual Firefox-on-Android default style; see https://github.com/necolas/normalize.css/issues/214 border: 1px solid transparent; white-space: nowrap; @include button-size($padding-base-vertical, $padding-base-horizontal, $font-size-base, $line-height-base, $btn-border-radius-base); @include user-select(none); &, &:active, &.active { &:focus, &.focus { @include tab-focus; } } &:hover, &:focus, &.focus { color: $btn-default-color; text-decoration: none; } &:active, &.active { outline: 0; background-image: none; @include box-shadow(inset 0 3px 5px rgba(0,0,0,.125)); } &.disabled, &[disabled], fieldset[disabled] & { cursor: $cursor-disabled; @include opacity(.65); @include box-shadow(none); } // [converter] extracted a& to a.btn } a.btn { &.disabled, fieldset[disabled] & { pointer-events: none; // Future-proof disabling of clicks on `` elements } } // Alternate buttons // -------------------------------------------------- .btn-default { @include button-variant($btn-default-color, $btn-default-bg, $btn-default-border); } .btn-primary { @include button-variant($btn-primary-color, $btn-primary-bg, $btn-primary-border); } // Success appears as green .btn-success { @include button-variant($btn-success-color, $btn-success-bg, $btn-success-border); } // Info appears as blue-green .btn-info { @include button-variant($btn-info-color, $btn-info-bg, $btn-info-border); } // Warning appears as orange .btn-warning { @include button-variant($btn-warning-color, $btn-warning-bg, $btn-warning-border); } // Danger and error appear as red .btn-danger { @include button-variant($btn-danger-color, $btn-danger-bg, $btn-danger-border); } // Link buttons // ------------------------- // Make a button look and behave like a link .btn-link { color: $link-color; font-weight: normal; border-radius: 0; &, &:active, &.active, &[disabled], fieldset[disabled] & { background-color: transparent; @include box-shadow(none); } &, &:hover, &:focus, &:active { border-color: transparent; } &:hover, &:focus { color: $link-hover-color; text-decoration: $link-hover-decoration; background-color: transparent; } &[disabled], fieldset[disabled] & { &:hover, &:focus { color: $btn-link-disabled-color; text-decoration: none; } } } // Button Sizes // -------------------------------------------------- .btn-lg { // line-height: ensure even-numbered height of button next to large input @include button-size($padding-large-vertical, $padding-large-horizontal, $font-size-large, $line-height-large, $btn-border-radius-large); } .btn-sm { // line-height: ensure proper height of button next to small input @include button-size($padding-small-vertical, $padding-small-horizontal, $font-size-small, $line-height-small, $btn-border-radius-small); } .btn-xs { @include button-size($padding-xs-vertical, $padding-xs-horizontal, $font-size-small, $line-height-small, $btn-border-radius-small); } // Block button // -------------------------------------------------- .btn-block { display: block; width: 100%; } // Vertically space out multiple block buttons .btn-block + .btn-block { margin-top: 5px; } // Specificity overrides input[type="submit"], input[type="reset"], input[type="button"] { &.btn-block { width: 100%; } } ================================================ FILE: client/src/style/vendor/bootstrap/_carousel.scss ================================================ // // Carousel // -------------------------------------------------- // Wrapper for the slide container and indicators .carousel { position: relative; } .carousel-inner { position: relative; overflow: hidden; width: 100%; > .item { display: none; position: relative; @include transition(.6s ease-in-out left); // Account for jankitude on images > img, > a > img { @include img-responsive; line-height: 1; } // WebKit CSS3 transforms for supported devices @media all and (transform-3d), (-webkit-transform-3d) { @include transition-transform(0.6s ease-in-out); @include backface-visibility(hidden); @include perspective(1000px); &.next, &.active.right { @include translate3d(100%, 0, 0); left: 0; } &.prev, &.active.left { @include translate3d(-100%, 0, 0); left: 0; } &.next.left, &.prev.right, &.active { @include translate3d(0, 0, 0); left: 0; } } } > .active, > .next, > .prev { display: block; } > .active { left: 0; } > .next, > .prev { position: absolute; top: 0; width: 100%; } > .next { left: 100%; } > .prev { left: -100%; } > .next.left, > .prev.right { left: 0; } > .active.left { left: -100%; } > .active.right { left: 100%; } } // Left/right controls for nav // --------------------------- .carousel-control { position: absolute; top: 0; left: 0; bottom: 0; width: $carousel-control-width; @include opacity($carousel-control-opacity); font-size: $carousel-control-font-size; color: $carousel-control-color; text-align: center; text-shadow: $carousel-text-shadow; background-color: rgba(0, 0, 0, 0); // Fix IE9 click-thru bug // We can't have this transition here because WebKit cancels the carousel // animation if you trip this while in the middle of another animation. // Set gradients for backgrounds &.left { @include gradient-horizontal($start-color: rgba(0,0,0,.5), $end-color: rgba(0,0,0,.0001)); } &.right { left: auto; right: 0; @include gradient-horizontal($start-color: rgba(0,0,0,.0001), $end-color: rgba(0,0,0,.5)); } // Hover/focus state &:hover, &:focus { outline: 0; color: $carousel-control-color; text-decoration: none; @include opacity(.9); } // Toggles .icon-prev, .icon-next, .glyphicon-chevron-left, .glyphicon-chevron-right { position: absolute; top: 50%; margin-top: -10px; z-index: 5; display: inline-block; } .icon-prev, .glyphicon-chevron-left { left: 50%; margin-left: -10px; } .icon-next, .glyphicon-chevron-right { right: 50%; margin-right: -10px; } .icon-prev, .icon-next { width: 20px; height: 20px; line-height: 1; font-family: serif; } .icon-prev { &:before { content: '\2039';// SINGLE LEFT-POINTING ANGLE QUOTATION MARK (U+2039) } } .icon-next { &:before { content: '\203a';// SINGLE RIGHT-POINTING ANGLE QUOTATION MARK (U+203A) } } } // Optional indicator pips // // Add an unordered list with the following class and add a list item for each // slide your carousel holds. .carousel-indicators { position: absolute; bottom: 10px; left: 50%; z-index: 15; width: 60%; margin-left: -30%; padding-left: 0; list-style: none; text-align: center; li { display: inline-block; width: 10px; height: 10px; margin: 1px; text-indent: -999px; border: 1px solid $carousel-indicator-border-color; border-radius: 10px; cursor: pointer; // IE8-9 hack for event handling // // Internet Explorer 8-9 does not support clicks on elements without a set // `background-color`. We cannot use `filter` since that's not viewed as a // background color by the browser. Thus, a hack is needed. // See https://developer.mozilla.org/en-US/docs/Web/Events/click#Internet_Explorer // // For IE8, we set solid black as it doesn't support `rgba()`. For IE9, we // set alpha transparency for the best results possible. background-color: #000 \9; // IE8 background-color: rgba(0,0,0,0); // IE9 } .active { margin: 0; width: 12px; height: 12px; background-color: $carousel-indicator-active-bg; } } // Optional captions // ----------------------------- // Hidden by default for smaller viewports .carousel-caption { position: absolute; left: 15%; right: 15%; bottom: 20px; z-index: 10; padding-top: 20px; padding-bottom: 20px; color: $carousel-caption-color; text-align: center; text-shadow: $carousel-text-shadow; & .btn { text-shadow: none; // No shadow for button elements in carousel-caption } } // Scale up controls for tablets and up @media screen and (min-width: $screen-sm-min) { // Scale up the controls a smidge .carousel-control { .glyphicon-chevron-left, .glyphicon-chevron-right, .icon-prev, .icon-next { width: ($carousel-control-font-size * 1.5); height: ($carousel-control-font-size * 1.5); margin-top: ($carousel-control-font-size / -2); font-size: ($carousel-control-font-size * 1.5); } .glyphicon-chevron-left, .icon-prev { margin-left: ($carousel-control-font-size / -2); } .glyphicon-chevron-right, .icon-next { margin-right: ($carousel-control-font-size / -2); } } // Show and left align the captions .carousel-caption { left: 20%; right: 20%; padding-bottom: 30px; } // Move up the indicators .carousel-indicators { bottom: 20px; } } ================================================ FILE: client/src/style/vendor/bootstrap/_close.scss ================================================ // // Close icons // -------------------------------------------------- .close { float: right; font-size: ($font-size-base * 1.5); font-weight: $close-font-weight; line-height: 1; color: $close-color; text-shadow: $close-text-shadow; @include opacity(.2); &:hover, &:focus { color: $close-color; text-decoration: none; cursor: pointer; @include opacity(.5); } // [converter] extracted button& to button.close } // Additional properties for button version // iOS requires the button element instead of an anchor tag. // If you want the anchor version, it requires `href="#"`. // See https://developer.mozilla.org/en-US/docs/Web/Events/click#Safari_Mobile button.close { padding: 0; cursor: pointer; background: transparent; border: 0; -webkit-appearance: none; } ================================================ FILE: client/src/style/vendor/bootstrap/_code.scss ================================================ // // Code (inline and block) // -------------------------------------------------- // Inline and block code styles code, kbd, pre, samp { font-family: $font-family-monospace; } // Inline code code { padding: 2px 4px; font-size: 90%; color: $code-color; background-color: $code-bg; border-radius: $border-radius-base; } // User input typically entered via keyboard kbd { padding: 2px 4px; font-size: 90%; color: $kbd-color; background-color: $kbd-bg; border-radius: $border-radius-small; box-shadow: inset 0 -1px 0 rgba(0,0,0,.25); kbd { padding: 0; font-size: 100%; font-weight: bold; box-shadow: none; } } // Blocks of code pre { display: block; padding: (($line-height-computed - 1) / 2); margin: 0 0 ($line-height-computed / 2); font-size: ($font-size-base - 1); // 14px to 13px line-height: $line-height-base; word-break: break-all; word-wrap: break-word; color: $pre-color; background-color: $pre-bg; border: 1px solid $pre-border-color; border-radius: $border-radius-base; // Account for some code outputs that place code tags in pre tags code { padding: 0; font-size: inherit; color: inherit; white-space: pre-wrap; background-color: transparent; border-radius: 0; } } // Enable scrollable blocks of code .pre-scrollable { max-height: $pre-scrollable-max-height; overflow-y: scroll; } ================================================ FILE: client/src/style/vendor/bootstrap/_component-animations.scss ================================================ // // Component animations // -------------------------------------------------- // Heads up! // // We don't use the `.opacity()` mixin here since it causes a bug with text // fields in IE7-8. Source: https://github.com/twbs/bootstrap/pull/3552. .fade { opacity: 0; @include transition(opacity .15s linear); &.in { opacity: 1; } } .collapse { display: none; &.in { display: block; } // [converter] extracted tr&.in to tr.collapse.in // [converter] extracted tbody&.in to tbody.collapse.in } tr.collapse.in { display: table-row; } tbody.collapse.in { display: table-row-group; } .collapsing { position: relative; height: 0; overflow: hidden; @include transition-property(height, visibility); @include transition-duration(.35s); @include transition-timing-function(ease); } ================================================ FILE: client/src/style/vendor/bootstrap/_dropdowns.scss ================================================ // // Dropdown menus // -------------------------------------------------- // Dropdown arrow/caret .caret { display: inline-block; width: 0; height: 0; margin-left: 2px; vertical-align: middle; border-top: $caret-width-base dashed; border-top: $caret-width-base solid \9; // IE8 border-right: $caret-width-base solid transparent; border-left: $caret-width-base solid transparent; } // The dropdown wrapper (div) .dropup, .dropdown { position: relative; } // Prevent the focus on the dropdown toggle when closing dropdowns .dropdown-toggle:focus { outline: 0; } // The dropdown menu (ul) .dropdown-menu { position: absolute; top: 100%; left: 0; z-index: $zindex-dropdown; display: none; // none by default, but block on "open" of the menu float: left; min-width: 160px; padding: 5px 0; margin: 2px 0 0; // override default ul list-style: none; font-size: $font-size-base; text-align: left; // Ensures proper alignment if parent has it changed (e.g., modal footer) background-color: $dropdown-bg; border: 1px solid $dropdown-fallback-border; // IE8 fallback border: 1px solid $dropdown-border; border-radius: $border-radius-base; @include box-shadow(0 6px 12px rgba(0,0,0,.175)); background-clip: padding-box; // Aligns the dropdown menu to right // // Deprecated as of 3.1.0 in favor of `.dropdown-menu-[dir]` &.pull-right { right: 0; left: auto; } // Dividers (basically an hr) within the dropdown .divider { @include nav-divider($dropdown-divider-bg); } // Links within the dropdown menu > li > a { display: block; padding: 3px 20px; clear: both; font-weight: normal; line-height: $line-height-base; color: $dropdown-link-color; white-space: nowrap; // prevent links from randomly breaking onto new lines } } // Hover/Focus state .dropdown-menu > li > a { &:hover, &:focus { text-decoration: none; color: $dropdown-link-hover-color; background-color: $dropdown-link-hover-bg; } } // Active state .dropdown-menu > .active > a { &, &:hover, &:focus { color: $dropdown-link-active-color; text-decoration: none; outline: 0; background-color: $dropdown-link-active-bg; } } // Disabled state // // Gray out text and ensure the hover/focus state remains gray .dropdown-menu > .disabled > a { &, &:hover, &:focus { color: $dropdown-link-disabled-color; } // Nuke hover/focus effects &:hover, &:focus { text-decoration: none; background-color: transparent; background-image: none; // Remove CSS gradient @include reset-filter; cursor: $cursor-disabled; } } // Open state for the dropdown .open { // Show the menu > .dropdown-menu { display: block; } // Remove the outline when :focus is triggered > a { outline: 0; } } // Menu positioning // // Add extra class to `.dropdown-menu` to flip the alignment of the dropdown // menu with the parent. .dropdown-menu-right { left: auto; // Reset the default from `.dropdown-menu` right: 0; } // With v3, we enabled auto-flipping if you have a dropdown within a right // aligned nav component. To enable the undoing of that, we provide an override // to restore the default dropdown menu alignment. // // This is only for left-aligning a dropdown menu within a `.navbar-right` or // `.pull-right` nav component. .dropdown-menu-left { left: 0; right: auto; } // Dropdown section headers .dropdown-header { display: block; padding: 3px 20px; font-size: $font-size-small; line-height: $line-height-base; color: $dropdown-header-color; white-space: nowrap; // as with > li > a } // Backdrop to catch body clicks on mobile, etc. .dropdown-backdrop { position: fixed; left: 0; right: 0; bottom: 0; top: 0; z-index: ($zindex-dropdown - 10); } // Right aligned dropdowns .pull-right > .dropdown-menu { right: 0; left: auto; } // Allow for dropdowns to go bottom up (aka, dropup-menu) // // Just add .dropup after the standard .dropdown class and you're set, bro. // TODO: abstract this so that the navbar fixed styles are not placed here? .dropup, .navbar-fixed-bottom .dropdown { // Reverse the caret .caret { border-top: 0; border-bottom: $caret-width-base dashed; border-bottom: $caret-width-base solid \9; // IE8 content: ""; } // Different positioning for bottom up menu .dropdown-menu { top: auto; bottom: 100%; margin-bottom: 2px; } } // Component alignment // // Reiterate per navbar.less and the modified component alignment there. @media (min-width: $grid-float-breakpoint) { .navbar-right { .dropdown-menu { right: 0; left: auto; } // Necessary for overrides of the default right aligned menu. // Will remove come v4 in all likelihood. .dropdown-menu-left { left: 0; right: auto; } } } ================================================ FILE: client/src/style/vendor/bootstrap/_forms.scss ================================================ // // Forms // -------------------------------------------------- // Normalize non-controls // // Restyle and baseline non-control form elements. fieldset { padding: 0; margin: 0; border: 0; // Chrome and Firefox set a `min-width: min-content;` on fieldsets, // so we reset that to ensure it behaves more like a standard block element. // See https://github.com/twbs/bootstrap/issues/12359. min-width: 0; } legend { display: block; width: 100%; padding: 0; margin-bottom: $line-height-computed; font-size: ($font-size-base * 1.5); line-height: inherit; color: $legend-color; border: 0; border-bottom: 1px solid $legend-border-color; } label { display: inline-block; max-width: 100%; // Force IE8 to wrap long content (see https://github.com/twbs/bootstrap/issues/13141) margin-bottom: 5px; font-weight: bold; } // Normalize form controls // // While most of our form styles require extra classes, some basic normalization // is required to ensure optimum display with or without those classes to better // address browser inconsistencies. // Override content-box in Normalize (* isn't specific enough) input[type="search"] { @include box-sizing(border-box); } // Position radios and checkboxes better input[type="radio"], input[type="checkbox"] { margin: 4px 0 0; margin-top: 1px \9; // IE8-9 line-height: normal; } input[type="file"] { display: block; } // Make range inputs behave like textual form controls input[type="range"] { display: block; width: 100%; } // Make multiple select elements height not fixed select[multiple], select[size] { height: auto; } // Focus for file, radio, and checkbox input[type="file"]:focus, input[type="radio"]:focus, input[type="checkbox"]:focus { @include tab-focus; } // Adjust output element output { display: block; padding-top: ($padding-base-vertical + 1); font-size: $font-size-base; line-height: $line-height-base; color: $input-color; } // Common form controls // // Shared size and type resets for form controls. Apply `.form-control` to any // of the following form controls: // // select // textarea // input[type="text"] // input[type="password"] // input[type="datetime"] // input[type="datetime-local"] // input[type="date"] // input[type="month"] // input[type="time"] // input[type="week"] // input[type="number"] // input[type="email"] // input[type="url"] // input[type="search"] // input[type="tel"] // input[type="color"] .form-control { display: block; width: 100%; height: $input-height-base; // Make inputs at least the height of their button counterpart (base line-height + padding + border) padding: $padding-base-vertical $padding-base-horizontal; font-size: $font-size-base; line-height: $line-height-base; color: $input-color; background-color: $input-bg; background-image: none; // Reset unusual Firefox-on-Android default style; see https://github.com/necolas/normalize.css/issues/214 border: 1px solid $input-border; border-radius: $input-border-radius; // Note: This has no effect on s in CSS. @include box-shadow(inset 0 1px 1px rgba(0,0,0,.075)); @include transition(border-color ease-in-out .15s, box-shadow ease-in-out .15s); // Customize the `:focus` state to imitate native WebKit styles. @include form-control-focus; // Placeholder @include placeholder; // Unstyle the caret on `` background color $input-bg: #fff !default; //** `` background color $input-bg-disabled: $gray-lighter !default; //** Text color for ``s $input-color: $gray !default; //** `` border color $input-border: #ccc !default; // TODO: Rename `$input-border-radius` to `$input-border-radius-base` in v4 //** Default `.form-control` border radius // This has no effect on ``s in CSS. $input-border-radius: $border-radius-base !default; //** Large `.form-control` border radius $input-border-radius-large: $border-radius-large !default; //** Small `.form-control` border radius $input-border-radius-small: $border-radius-small !default; //** Border color for inputs on focus $input-border-focus: #66afe9 !default; //** Placeholder text color $input-color-placeholder: #999 !default; //** Default `.form-control` height $input-height-base: ($line-height-computed + ($padding-base-vertical * 2) + 2) !default; //** Large `.form-control` height $input-height-large: (ceil($font-size-large * $line-height-large) + ($padding-large-vertical * 2) + 2) !default; //** Small `.form-control` height $input-height-small: (floor($font-size-small * $line-height-small) + ($padding-small-vertical * 2) + 2) !default; //** `.form-group` margin $form-group-margin-bottom: 15px !default; $legend-color: $gray-dark !default; $legend-border-color: #e5e5e5 !default; //** Background color for textual input addons $input-group-addon-bg: $gray-lighter !default; //** Border color for textual input addons $input-group-addon-border-color: $input-border !default; //** Disabled cursor for form controls and buttons. $cursor-disabled: not-allowed !default; //== Dropdowns // //## Dropdown menu container and contents. //** Background for the dropdown menu. $dropdown-bg: #fff !default; //** Dropdown menu `border-color`. $dropdown-border: rgba(0,0,0,.15) !default; //** Dropdown menu `border-color` **for IE8**. $dropdown-fallback-border: #ccc !default; //** Divider color for between dropdown items. $dropdown-divider-bg: #e5e5e5 !default; //** Dropdown link text color. $dropdown-link-color: $gray-dark !default; //** Hover color for dropdown links. $dropdown-link-hover-color: darken($gray-dark, 5%) !default; //** Hover background for dropdown links. $dropdown-link-hover-bg: #f5f5f5 !default; //** Active dropdown menu item text color. $dropdown-link-active-color: $component-active-color !default; //** Active dropdown menu item background color. $dropdown-link-active-bg: $component-active-bg !default; //** Disabled dropdown menu item background color. $dropdown-link-disabled-color: $gray-light !default; //** Text color for headers within dropdown menus. $dropdown-header-color: $gray-light !default; //** Deprecated `$dropdown-caret-color` as of v3.1.0 $dropdown-caret-color: #000 !default; //-- Z-index master list // // Warning: Avoid customizing these values. They're used for a bird's eye view // of components dependent on the z-axis and are designed to all work together. // // Note: These variables are not generated into the Customizer. $zindex-navbar: 1000 !default; $zindex-dropdown: 1000 !default; $zindex-popover: 1060 !default; $zindex-tooltip: 1070 !default; $zindex-navbar-fixed: 1030 !default; $zindex-modal-background: 1040 !default; $zindex-modal: 1050 !default; //== Media queries breakpoints // //## Define the breakpoints at which your layout will change, adapting to different screen sizes. // Extra small screen / phone //** Deprecated `$screen-xs` as of v3.0.1 $screen-xs: 480px !default; //** Deprecated `$screen-xs-min` as of v3.2.0 $screen-xs-min: $screen-xs !default; //** Deprecated `$screen-phone` as of v3.0.1 $screen-phone: $screen-xs-min !default; // Small screen / tablet //** Deprecated `$screen-sm` as of v3.0.1 $screen-sm: 768px !default; $screen-sm-min: $screen-sm !default; //** Deprecated `$screen-tablet` as of v3.0.1 $screen-tablet: $screen-sm-min !default; // Medium screen / desktop //** Deprecated `$screen-md` as of v3.0.1 $screen-md: 992px !default; $screen-md-min: $screen-md !default; //** Deprecated `$screen-desktop` as of v3.0.1 $screen-desktop: $screen-md-min !default; // Large screen / wide desktop //** Deprecated `$screen-lg` as of v3.0.1 $screen-lg: 1200px !default; $screen-lg-min: $screen-lg !default; //** Deprecated `$screen-lg-desktop` as of v3.0.1 $screen-lg-desktop: $screen-lg-min !default; // So media queries don't overlap when required, provide a maximum $screen-xs-max: ($screen-sm-min - 1) !default; $screen-sm-max: ($screen-md-min - 1) !default; $screen-md-max: ($screen-lg-min - 1) !default; //== Grid system // //## Define your custom responsive grid. //** Number of columns in the grid. $grid-columns: 12 !default; //** Padding between columns. Gets divided in half for the left and right. $grid-gutter-width: 30px !default; // Navbar collapse //** Point at which the navbar becomes uncollapsed. $grid-float-breakpoint: $screen-sm-min !default; //** Point at which the navbar begins collapsing. $grid-float-breakpoint-max: ($grid-float-breakpoint - 1) !default; //== Container sizes // //## Define the maximum width of `.container` for different screen sizes. // Small screen / tablet $container-tablet: (720px + $grid-gutter-width) !default; //** For `$screen-sm-min` and up. $container-sm: $container-tablet !default; // Medium screen / desktop $container-desktop: (940px + $grid-gutter-width) !default; //** For `$screen-md-min` and up. $container-md: $container-desktop !default; // Large screen / wide desktop $container-large-desktop: (1140px + $grid-gutter-width) !default; //** For `$screen-lg-min` and up. $container-lg: $container-large-desktop !default; //== Navbar // //## // Basics of a navbar $navbar-height: 50px !default; $navbar-margin-bottom: $line-height-computed !default; $navbar-border-radius: $border-radius-base !default; $navbar-padding-horizontal: floor(($grid-gutter-width / 2)) !default; $navbar-padding-vertical: (($navbar-height - $line-height-computed) / 2) !default; $navbar-collapse-max-height: 340px !default; $navbar-default-color: #777 !default; $navbar-default-bg: #f8f8f8 !default; $navbar-default-border: darken($navbar-default-bg, 6.5%) !default; // Navbar links $navbar-default-link-color: #777 !default; $navbar-default-link-hover-color: #333 !default; $navbar-default-link-hover-bg: transparent !default; $navbar-default-link-active-color: #555 !default; $navbar-default-link-active-bg: darken($navbar-default-bg, 6.5%) !default; $navbar-default-link-disabled-color: #ccc !default; $navbar-default-link-disabled-bg: transparent !default; // Navbar brand label $navbar-default-brand-color: $navbar-default-link-color !default; $navbar-default-brand-hover-color: darken($navbar-default-brand-color, 10%) !default; $navbar-default-brand-hover-bg: transparent !default; // Navbar toggle $navbar-default-toggle-hover-bg: #ddd !default; $navbar-default-toggle-icon-bar-bg: #888 !default; $navbar-default-toggle-border-color: #ddd !default; //=== Inverted navbar // Reset inverted navbar basics $navbar-inverse-color: lighten($gray-light, 15%) !default; $navbar-inverse-bg: #222 !default; $navbar-inverse-border: darken($navbar-inverse-bg, 10%) !default; // Inverted navbar links $navbar-inverse-link-color: lighten($gray-light, 15%) !default; $navbar-inverse-link-hover-color: #fff !default; $navbar-inverse-link-hover-bg: transparent !default; $navbar-inverse-link-active-color: $navbar-inverse-link-hover-color !default; $navbar-inverse-link-active-bg: darken($navbar-inverse-bg, 10%) !default; $navbar-inverse-link-disabled-color: #444 !default; $navbar-inverse-link-disabled-bg: transparent !default; // Inverted navbar brand label $navbar-inverse-brand-color: $navbar-inverse-link-color !default; $navbar-inverse-brand-hover-color: #fff !default; $navbar-inverse-brand-hover-bg: transparent !default; // Inverted navbar toggle $navbar-inverse-toggle-hover-bg: #333 !default; $navbar-inverse-toggle-icon-bar-bg: #fff !default; $navbar-inverse-toggle-border-color: #333 !default; //== Navs // //## //=== Shared nav styles $nav-link-padding: 10px 15px !default; $nav-link-hover-bg: $gray-lighter !default; $nav-disabled-link-color: $gray-light !default; $nav-disabled-link-hover-color: $gray-light !default; //== Tabs $nav-tabs-border-color: #ddd !default; $nav-tabs-link-hover-border-color: $gray-lighter !default; $nav-tabs-active-link-hover-bg: $body-bg !default; $nav-tabs-active-link-hover-color: $gray !default; $nav-tabs-active-link-hover-border-color: #ddd !default; $nav-tabs-justified-link-border-color: #ddd !default; $nav-tabs-justified-active-link-border-color: $body-bg !default; //== Pills $nav-pills-border-radius: $border-radius-base !default; $nav-pills-active-link-hover-bg: $component-active-bg !default; $nav-pills-active-link-hover-color: $component-active-color !default; //== Pagination // //## $pagination-color: $link-color !default; $pagination-bg: #fff !default; $pagination-border: #ddd !default; $pagination-hover-color: $link-hover-color !default; $pagination-hover-bg: $gray-lighter !default; $pagination-hover-border: #ddd !default; $pagination-active-color: #fff !default; $pagination-active-bg: $brand-primary !default; $pagination-active-border: $brand-primary !default; $pagination-disabled-color: $gray-light !default; $pagination-disabled-bg: #fff !default; $pagination-disabled-border: #ddd !default; //== Pager // //## $pager-bg: $pagination-bg !default; $pager-border: $pagination-border !default; $pager-border-radius: 15px !default; $pager-hover-bg: $pagination-hover-bg !default; $pager-active-bg: $pagination-active-bg !default; $pager-active-color: $pagination-active-color !default; $pager-disabled-color: $pagination-disabled-color !default; //== Jumbotron // //## $jumbotron-padding: 30px !default; $jumbotron-color: inherit !default; $jumbotron-bg: $gray-lighter !default; $jumbotron-heading-color: inherit !default; $jumbotron-font-size: ceil(($font-size-base * 1.5)) !default; $jumbotron-heading-font-size: ceil(($font-size-base * 4.5)) !default; //== Form states and alerts // //## Define colors for form feedback states and, by default, alerts. $state-success-text: #3c763d !default; $state-success-bg: #dff0d8 !default; $state-success-border: darken(adjust-hue($state-success-bg, -10), 5%) !default; $state-info-text: #31708f !default; $state-info-bg: #d9edf7 !default; $state-info-border: darken(adjust-hue($state-info-bg, -10), 7%) !default; $state-warning-text: #8a6d3b !default; $state-warning-bg: #fcf8e3 !default; $state-warning-border: darken(adjust-hue($state-warning-bg, -10), 5%) !default; $state-danger-text: #a94442 !default; $state-danger-bg: #f2dede !default; $state-danger-border: darken(adjust-hue($state-danger-bg, -10), 5%) !default; //== Tooltips // //## //** Tooltip max width $tooltip-max-width: 200px !default; //** Tooltip text color $tooltip-color: #fff !default; //** Tooltip background color $tooltip-bg: #000 !default; $tooltip-opacity: .9 !default; //** Tooltip arrow width $tooltip-arrow-width: 5px !default; //** Tooltip arrow color $tooltip-arrow-color: $tooltip-bg !default; //== Popovers // //## //** Popover body background color $popover-bg: #fff !default; //** Popover maximum width $popover-max-width: 276px !default; //** Popover border color $popover-border-color: rgba(0,0,0,.2) !default; //** Popover fallback border color $popover-fallback-border-color: #ccc !default; //** Popover title background color $popover-title-bg: darken($popover-bg, 3%) !default; //** Popover arrow width $popover-arrow-width: 10px !default; //** Popover arrow color $popover-arrow-color: $popover-bg !default; //** Popover outer arrow width $popover-arrow-outer-width: ($popover-arrow-width + 1) !default; //** Popover outer arrow color $popover-arrow-outer-color: fade_in($popover-border-color, 0.05) !default; //** Popover outer arrow fallback color $popover-arrow-outer-fallback-color: darken($popover-fallback-border-color, 20%) !default; //== Labels // //## //** Default label background color $label-default-bg: $gray-light !default; //** Primary label background color $label-primary-bg: $brand-primary !default; //** Success label background color $label-success-bg: $brand-success !default; //** Info label background color $label-info-bg: $brand-info !default; //** Warning label background color $label-warning-bg: $brand-warning !default; //** Danger label background color $label-danger-bg: $brand-danger !default; //** Default label text color $label-color: #fff !default; //** Default text color of a linked label $label-link-hover-color: #fff !default; //== Modals // //## //** Padding applied to the modal body $modal-inner-padding: 15px !default; //** Padding applied to the modal title $modal-title-padding: 15px !default; //** Modal title line-height $modal-title-line-height: $line-height-base !default; //** Background color of modal content area $modal-content-bg: #fff !default; //** Modal content border color $modal-content-border-color: rgba(0,0,0,.2) !default; //** Modal content border color **for IE8** $modal-content-fallback-border-color: #999 !default; //** Modal backdrop background color $modal-backdrop-bg: #000 !default; //** Modal backdrop opacity $modal-backdrop-opacity: .5 !default; //** Modal header border color $modal-header-border-color: #e5e5e5 !default; //** Modal footer border color $modal-footer-border-color: $modal-header-border-color !default; $modal-lg: 900px !default; $modal-md: 600px !default; $modal-sm: 300px !default; //== Alerts // //## Define alert colors, border radius, and padding. $alert-padding: 15px !default; $alert-border-radius: $border-radius-base !default; $alert-link-font-weight: bold !default; $alert-success-bg: $state-success-bg !default; $alert-success-text: $state-success-text !default; $alert-success-border: $state-success-border !default; $alert-info-bg: $state-info-bg !default; $alert-info-text: $state-info-text !default; $alert-info-border: $state-info-border !default; $alert-warning-bg: $state-warning-bg !default; $alert-warning-text: $state-warning-text !default; $alert-warning-border: $state-warning-border !default; $alert-danger-bg: $state-danger-bg !default; $alert-danger-text: $state-danger-text !default; $alert-danger-border: $state-danger-border !default; //== Progress bars // //## //** Background color of the whole progress component $progress-bg: #f5f5f5 !default; //** Progress bar text color $progress-bar-color: #fff !default; //** Variable for setting rounded corners on progress bar. $progress-border-radius: $border-radius-base !default; //** Default progress bar color $progress-bar-bg: $brand-primary !default; //** Success progress bar color $progress-bar-success-bg: $brand-success !default; //** Warning progress bar color $progress-bar-warning-bg: $brand-warning !default; //** Danger progress bar color $progress-bar-danger-bg: $brand-danger !default; //** Info progress bar color $progress-bar-info-bg: $brand-info !default; //== List group // //## //** Background color on `.list-group-item` $list-group-bg: #fff !default; //** `.list-group-item` border color $list-group-border: #ddd !default; //** List group border radius $list-group-border-radius: $border-radius-base !default; //** Background color of single list items on hover $list-group-hover-bg: #f5f5f5 !default; //** Text color of active list items $list-group-active-color: $component-active-color !default; //** Background color of active list items $list-group-active-bg: $component-active-bg !default; //** Border color of active list elements $list-group-active-border: $list-group-active-bg !default; //** Text color for content within active list items $list-group-active-text-color: lighten($list-group-active-bg, 40%) !default; //** Text color of disabled list items $list-group-disabled-color: $gray-light !default; //** Background color of disabled list items $list-group-disabled-bg: $gray-lighter !default; //** Text color for content within disabled list items $list-group-disabled-text-color: $list-group-disabled-color !default; $list-group-link-color: #555 !default; $list-group-link-hover-color: $list-group-link-color !default; $list-group-link-heading-color: #333 !default; //== Panels // //## $panel-bg: #fff !default; $panel-body-padding: 15px !default; $panel-heading-padding: 10px 15px !default; $panel-footer-padding: $panel-heading-padding !default; $panel-border-radius: $border-radius-base !default; //** Border color for elements within panels $panel-inner-border: #ddd !default; $panel-footer-bg: #f5f5f5 !default; $panel-default-text: $gray-dark !default; $panel-default-border: #ddd !default; $panel-default-heading-bg: #f5f5f5 !default; $panel-primary-text: #fff !default; $panel-primary-border: $brand-primary !default; $panel-primary-heading-bg: $brand-primary !default; $panel-success-text: $state-success-text !default; $panel-success-border: $state-success-border !default; $panel-success-heading-bg: $state-success-bg !default; $panel-info-text: $state-info-text !default; $panel-info-border: $state-info-border !default; $panel-info-heading-bg: $state-info-bg !default; $panel-warning-text: $state-warning-text !default; $panel-warning-border: $state-warning-border !default; $panel-warning-heading-bg: $state-warning-bg !default; $panel-danger-text: $state-danger-text !default; $panel-danger-border: $state-danger-border !default; $panel-danger-heading-bg: $state-danger-bg !default; //== Thumbnails // //## //** Padding around the thumbnail image $thumbnail-padding: 4px !default; //** Thumbnail background color $thumbnail-bg: $body-bg !default; //** Thumbnail border color $thumbnail-border: #ddd !default; //** Thumbnail border radius $thumbnail-border-radius: $border-radius-base !default; //** Custom text color for thumbnail captions $thumbnail-caption-color: $text-color !default; //** Padding around the thumbnail caption $thumbnail-caption-padding: 9px !default; //== Wells // //## $well-bg: #f5f5f5 !default; $well-border: darken($well-bg, 7%) !default; //== Badges // //## $badge-color: #fff !default; //** Linked badge text color on hover $badge-link-hover-color: #fff !default; $badge-bg: $gray-light !default; //** Badge text color in active nav link $badge-active-color: $link-color !default; //** Badge background color in active nav link $badge-active-bg: #fff !default; $badge-font-weight: bold !default; $badge-line-height: 1 !default; $badge-border-radius: 10px !default; //== Breadcrumbs // //## $breadcrumb-padding-vertical: 8px !default; $breadcrumb-padding-horizontal: 15px !default; //** Breadcrumb background color $breadcrumb-bg: #f5f5f5 !default; //** Breadcrumb text color $breadcrumb-color: #ccc !default; //** Text color of current page in the breadcrumb $breadcrumb-active-color: $gray-light !default; //** Textual separator for between breadcrumb elements $breadcrumb-separator: "/" !default; //== Carousel // //## $carousel-text-shadow: 0 1px 2px rgba(0,0,0,.6) !default; $carousel-control-color: #fff !default; $carousel-control-width: 15% !default; $carousel-control-opacity: .5 !default; $carousel-control-font-size: 20px !default; $carousel-indicator-active-bg: #fff !default; $carousel-indicator-border-color: #fff !default; $carousel-caption-color: #fff !default; //== Close // //## $close-font-weight: bold !default; $close-color: #000 !default; $close-text-shadow: 0 1px 0 #fff !default; //== Code // //## $code-color: #c7254e !default; $code-bg: #f9f2f4 !default; $kbd-color: #fff !default; $kbd-bg: #333 !default; $pre-bg: #f5f5f5 !default; $pre-color: $gray-dark !default; $pre-border-color: #ccc !default; $pre-scrollable-max-height: 340px !default; //== Type // //## //** Horizontal offset for forms and lists. $component-offset-horizontal: 180px !default; //** Text muted color $text-muted: $gray-light !default; //** Abbreviations and acronyms border color $abbr-border-color: $gray-light !default; //** Headings small color $headings-small-color: $gray-light !default; //** Blockquote small color $blockquote-small-color: $gray-light !default; //** Blockquote font size $blockquote-font-size: ($font-size-base * 1.25) !default; //** Blockquote border color $blockquote-border-color: $gray-lighter !default; //** Page header border color $page-header-border-color: $gray-lighter !default; //** Width of horizontal description list titles $dl-horizontal-offset: $component-offset-horizontal !default; //** Point at which .dl-horizontal becomes horizontal $dl-horizontal-breakpoint: $grid-float-breakpoint !default; //** Horizontal line color. $hr-border: $gray-lighter !default; ================================================ FILE: client/src/style/vendor/bootstrap/_wells.scss ================================================ // // Wells // -------------------------------------------------- // Base class .well { min-height: 20px; padding: 19px; margin-bottom: 20px; background-color: $well-bg; border: 1px solid $well-border; border-radius: $border-radius-base; @include box-shadow(inset 0 1px 1px rgba(0,0,0,.05)); blockquote { border-color: #ddd; border-color: rgba(0,0,0,.15); } } // Sizes .well-lg { padding: 24px; border-radius: $border-radius-large; } .well-sm { padding: 9px; border-radius: $border-radius-small; } ================================================ FILE: client/src/style/vendor/bootstrap/mixins/_alerts.scss ================================================ // Alerts @mixin alert-variant($background, $border, $text-color) { background-color: $background; border-color: $border; color: $text-color; hr { border-top-color: darken($border, 5%); } .alert-link { color: darken($text-color, 10%); } } ================================================ FILE: client/src/style/vendor/bootstrap/mixins/_background-variant.scss ================================================ // Contextual backgrounds // [converter] $parent hack @mixin bg-variant($parent, $color) { #{$parent} { background-color: $color; } a#{$parent}:hover, a#{$parent}:focus { background-color: darken($color, 10%); } } ================================================ FILE: client/src/style/vendor/bootstrap/mixins/_border-radius.scss ================================================ // Single side border-radius @mixin border-top-radius($radius) { border-top-right-radius: $radius; border-top-left-radius: $radius; } @mixin border-right-radius($radius) { border-bottom-right-radius: $radius; border-top-right-radius: $radius; } @mixin border-bottom-radius($radius) { border-bottom-right-radius: $radius; border-bottom-left-radius: $radius; } @mixin border-left-radius($radius) { border-bottom-left-radius: $radius; border-top-left-radius: $radius; } ================================================ FILE: client/src/style/vendor/bootstrap/mixins/_buttons.scss ================================================ // Button variants // // Easily pump out default styles, as well as :hover, :focus, :active, // and disabled options for all buttons @mixin button-variant($color, $background, $border) { color: $color; background-color: $background; border-color: $border; &:focus, &.focus { color: $color; background-color: darken($background, 10%); border-color: darken($border, 25%); } &:hover { color: $color; background-color: darken($background, 10%); border-color: darken($border, 12%); } &:active, &.active, .open > &.dropdown-toggle { color: $color; background-color: darken($background, 10%); border-color: darken($border, 12%); &:hover, &:focus, &.focus { color: $color; background-color: darken($background, 17%); border-color: darken($border, 25%); } } &:active, &.active, .open > &.dropdown-toggle { background-image: none; } &.disabled, &[disabled], fieldset[disabled] & { &:hover, &:focus, &.focus { background-color: $background; border-color: $border; } } .badge { color: $background; background-color: $color; } } // Button sizes @mixin button-size($padding-vertical, $padding-horizontal, $font-size, $line-height, $border-radius) { padding: $padding-vertical $padding-horizontal; font-size: $font-size; line-height: $line-height; border-radius: $border-radius; } ================================================ FILE: client/src/style/vendor/bootstrap/mixins/_center-block.scss ================================================ // Center-align a block level element @mixin center-block() { display: block; margin-left: auto; margin-right: auto; } ================================================ FILE: client/src/style/vendor/bootstrap/mixins/_clearfix.scss ================================================ // Clearfix // // For modern browsers // 1. The space content is one way to avoid an Opera bug when the // contenteditable attribute is included anywhere else in the document. // Otherwise it causes space to appear at the top and bottom of elements // that are clearfixed. // 2. The use of `table` rather than `block` is only necessary if using // `:before` to contain the top-margins of child elements. // // Source: http://nicolasgallagher.com/micro-clearfix-hack/ @mixin clearfix() { &:before, &:after { content: " "; // 1 display: table; // 2 } &:after { clear: both; } } ================================================ FILE: client/src/style/vendor/bootstrap/mixins/_forms.scss ================================================ // Form validation states // // Used in forms.less to generate the form validation CSS for warnings, errors, // and successes. @mixin form-control-validation($text-color: #555, $border-color: #ccc, $background-color: #f5f5f5) { // Color the label and help text .help-block, .control-label, .radio, .checkbox, .radio-inline, .checkbox-inline, &.radio label, &.checkbox label, &.radio-inline label, &.checkbox-inline label { color: $text-color; } // Set the border and box shadow on specific inputs to match .form-control { border-color: $border-color; @include box-shadow(inset 0 1px 1px rgba(0,0,0,.075)); // Redeclare so transitions work &:focus { border-color: darken($border-color, 10%); $shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 6px lighten($border-color, 20%); @include box-shadow($shadow); } } // Set validation states also for addons .input-group-addon { color: $text-color; border-color: $border-color; background-color: $background-color; } // Optional feedback icon .form-control-feedback { color: $text-color; } } // Form control focus state // // Generate a customized focus state and for any input with the specified color, // which defaults to the `$input-border-focus` variable. // // We highly encourage you to not customize the default value, but instead use // this to tweak colors on an as-needed basis. This aesthetic change is based on // WebKit's default styles, but applicable to a wider range of browsers. Its // usability and accessibility should be taken into account with any change. // // Example usage: change the default blue border and shadow to white for better // contrast against a dark gray background. @mixin form-control-focus($color: $input-border-focus) { $color-rgba: rgba(red($color), green($color), blue($color), .6); &:focus { border-color: $color; outline: 0; @include box-shadow(inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px $color-rgba); } } // Form control sizing // // Relative text size, padding, and border-radii changes for form controls. For // horizontal sizing, wrap controls in the predefined grid classes. `