├── .babelrc ├── .eslintrc ├── .github └── workflows │ └── semgrep.yml ├── .gitignore ├── .npmignore ├── LICENSE ├── README.md ├── app ├── components │ ├── application │ │ ├── application.pug │ │ ├── application.styl │ │ └── index.js │ ├── base-component.js │ ├── base-screenshot │ │ ├── arrow-bottom-left.svg │ │ ├── arrow-bottom-right.svg │ │ ├── arrow-top-left.svg │ │ ├── arrow-top-right.svg │ │ ├── base-screenshot.pug │ │ ├── index.js │ │ ├── mixin-annotation-arrow.pug │ │ └── screenshot-iframe.styl │ ├── base-target │ │ ├── after-content.pug │ │ ├── base-target.pug │ │ ├── base-target.svg │ │ ├── before-content.pug │ │ ├── download-link.pug │ │ ├── index.js │ │ └── title.pug │ ├── icons │ │ ├── clear.svg │ │ ├── close.svg │ │ ├── collapse.svg │ │ ├── copy.svg │ │ ├── index.js │ │ ├── next.svg │ │ ├── previous.svg │ │ └── search.svg │ ├── target-search │ │ ├── index.js │ │ ├── target-search.pug │ │ └── target-search.styl │ └── target-wrapper │ │ ├── index.js │ │ ├── screenshot.styl │ │ ├── target-wrapper.pug │ │ └── target-wrapper.styl ├── embed-box-base.js ├── embed-box.styl ├── iframe.styl ├── lib │ ├── create-stylesheet-template.js │ ├── create-theme-stylesheet.js │ ├── custom-event.js │ ├── key-map.js │ ├── request-animation-frame.js │ ├── routing.js │ ├── store.js │ └── to-dash-case.js ├── shared.styl ├── site │ ├── assets │ │ ├── customize-feature.png │ │ ├── documentation-feature.png │ │ ├── dotted.png │ │ ├── eager-logo.svg │ │ ├── examples │ │ │ ├── drupal-plugin.zip │ │ │ ├── joomla-plugin.zip │ │ │ ├── library.js │ │ │ ├── library.zip │ │ │ ├── weebly-library.js │ │ │ └── wordpress-plugin.zip │ │ ├── favicon.png │ │ ├── got-plugins-feature.png │ │ └── logo.png │ ├── documentation.pug │ ├── examples │ │ ├── advanced.md │ │ ├── asset-path.md │ │ ├── auto-show.md │ │ ├── basic-node.md │ │ ├── basic-web.md │ │ ├── basic.md │ │ ├── container-element.md │ │ ├── container-selector.md │ │ ├── content-slots.md │ │ ├── custom-install.md │ │ ├── custom-stylesheet.md │ │ ├── custom-target.md │ │ ├── custom-theme.md │ │ ├── events.md │ │ ├── get-target-ids.md │ │ ├── initial-target.md │ │ ├── install-node.md │ │ ├── install-web.md │ │ ├── labels.md │ │ ├── ordering.md │ │ ├── plugin-url.md │ │ └── routing.md │ ├── globals │ │ ├── embed-box-custom-target.js │ │ ├── embed-box-custom.js │ │ └── embed-box.js │ ├── index.js │ ├── index.pug │ ├── lib │ │ ├── is-element-partially-in-viewport.js │ │ ├── load-scripts.js │ │ ├── render-support-table.js │ │ ├── render-toc.js │ │ └── user-simulator.js │ ├── segment.js │ ├── share-icons.pug │ └── site.styl ├── styl │ ├── body-typography.styl │ ├── box-sizing-border-box-all.styl │ ├── buttons.styl │ ├── code-colors.styl │ ├── code-syntax-highlighting.styl │ ├── colors.styl │ ├── copyable-code.styl │ ├── font-smoothing.styl │ ├── fonts.styl │ ├── inline-code.styl │ ├── inline-svg.styl │ ├── link-underlines.styl │ ├── loading-dots.styl │ ├── markdown.styl │ ├── media-query-variables.styl │ ├── more-links-and-buttons.styl │ ├── reset.styl │ └── sizes.styl └── targets │ ├── drupal │ ├── activate-plugin.png │ ├── drupal-7 │ │ ├── activate-module │ │ │ ├── activate-module.pug │ │ │ ├── activate-module.styl │ │ │ └── index.js │ │ ├── drupal-7.pug │ │ ├── index.js │ │ ├── install-new-modules │ │ │ ├── index.js │ │ │ ├── install-new-modules.pug │ │ │ └── install-new-modules.styl │ │ ├── installation-successful │ │ │ ├── index.js │ │ │ ├── installation-successful.pug │ │ │ └── installation-successful.styl │ │ ├── navigate-to-modules │ │ │ ├── index.js │ │ │ ├── navigate-to-modules.pug │ │ │ └── navigate-to-modules.styl │ │ └── upload-module │ │ │ ├── index.js │ │ │ ├── upload-modules.pug │ │ │ └── upload-modules.styl │ ├── drupal-8 │ │ ├── activate-module │ │ │ ├── activate-module.pug │ │ │ ├── activate-module.styl │ │ │ └── index.js │ │ ├── drupal-8.pug │ │ ├── index.js │ │ ├── install-new-modules │ │ │ ├── index.js │ │ │ ├── install-new-modules.pug │ │ │ └── install-new-modules.styl │ │ ├── navigate-to-modules │ │ │ ├── index.js │ │ │ ├── navigate-to-modules.pug │ │ │ └── navigate-to-modules.styl │ │ └── upload-module │ │ │ ├── index.js │ │ │ ├── upload-modules.pug │ │ │ └── upload-modules.styl │ ├── drupal.svg │ ├── index.js │ └── upload-plugin.png │ ├── generic │ ├── generic-latest │ │ ├── generic-latest.pug │ │ ├── index.js │ │ └── install-script │ │ │ ├── index.js │ │ │ ├── install-script.pug │ │ │ └── install-script.styl │ └── index.js │ ├── index.js │ ├── joomla │ ├── activate-plugin.png │ ├── choose-file.png │ ├── choose-template.png │ ├── index.js │ ├── insert-code-body.png │ ├── insert-code-head.png │ ├── joomla-3-6-x.pug │ ├── joomla.svg │ ├── open-templates.png │ ├── save.png │ └── upload-plugin.png │ ├── shopify │ ├── index.js │ ├── shopify-latest │ │ ├── choose-template.png │ │ ├── edit-template.png │ │ ├── index.js │ │ ├── install-script │ │ │ ├── index.js │ │ │ ├── install-script.pug │ │ │ └── install-script.styl │ │ └── shopify-latest.pug │ └── shopify.svg │ ├── squarespace │ ├── index.js │ ├── squarespace-latest │ │ ├── index.js │ │ ├── install-script │ │ │ ├── index.js │ │ │ ├── install-script.pug │ │ │ └── install-script.styl │ │ └── squarespace-latest.pug │ └── squarespace.svg │ ├── tumblr │ ├── index.js │ ├── tumblr-latest │ │ ├── edit-appearance.png │ │ ├── edit-html.png │ │ ├── edit-theme.png │ │ ├── index.js │ │ ├── install-script │ │ │ ├── index.js │ │ │ ├── install-script.pug │ │ │ └── install-script.styl │ │ └── tumblr-latest.pug │ └── tumblr.svg │ ├── weebly │ ├── index.js │ ├── paste-embed-code-footer.png │ ├── paste-embed-code-header.png │ ├── weebly-latest.pug │ └── weebly.svg │ └── wordpress │ ├── activate-plugin.png │ ├── index.js │ ├── upload-plugin.png │ ├── wordpress-4.pug │ └── wordpress.svg ├── bower.json ├── circle.yml ├── custom-target.js ├── custom.js ├── deploy.yaml ├── dist ├── assets.zip ├── assets │ └── app │ │ └── targets │ │ ├── joomla │ │ ├── activate-plugin.png │ │ ├── choose-file.png │ │ ├── choose-template.png │ │ ├── insert-code-body.png │ │ ├── insert-code-head.png │ │ ├── open-templates.png │ │ ├── save.png │ │ └── upload-plugin.png │ │ ├── shopify │ │ └── shopify-latest │ │ │ ├── choose-template.png │ │ │ └── edit-template.png │ │ ├── tumblr │ │ └── tumblr-latest │ │ │ ├── edit-appearance.png │ │ │ ├── edit-html.png │ │ │ └── edit-theme.png │ │ ├── weebly │ │ ├── paste-embed-code-footer.png │ │ └── paste-embed-code-header.png │ │ └── wordpress │ │ ├── activate-plugin.png │ │ └── upload-plugin.png ├── embed-box-custom-target.js ├── embed-box-custom-target.map ├── embed-box-custom-target.min.js ├── embed-box-custom-target.min.map ├── embed-box-custom.js ├── embed-box-custom.map ├── embed-box-custom.min.js ├── embed-box-custom.min.map ├── embed-box.js ├── embed-box.map ├── embed-box.min.js └── embed-box.min.map ├── docs ├── design-architecture.md └── new-targets.md ├── embed-box.js ├── media ├── annotation-assets.png ├── annotation-assets.sketch │ ├── Data │ ├── QuickLook │ │ ├── Preview.png │ │ └── Thumbnail.png │ ├── metadata │ └── version ├── customize-feature │ ├── assets │ │ ├── blue.png │ │ ├── green.png │ │ ├── orange.png │ │ ├── purple.png │ │ └── red.png │ └── customize-feature.sketch │ │ ├── Data │ │ ├── QuickLook │ │ ├── Preview.png │ │ └── Thumbnail.png │ │ ├── metadata │ │ └── version ├── favicon.sketch │ ├── Data │ ├── QuickLook │ │ ├── Preview.png │ │ └── Thumbnail.png │ ├── metadata │ └── version ├── generic.sketch │ ├── Data │ ├── QuickLook │ │ ├── Preview.png │ │ └── Thumbnail.png │ ├── metadata │ └── version ├── icons.sketch ├── logo-alt.png ├── logo-alt.sketch ├── logo.png ├── logo.sketch │ ├── Data │ ├── QuickLook │ │ ├── Preview.png │ │ └── Thumbnail.png │ ├── metadata │ └── version └── shopify-icon.sketch │ ├── Data │ ├── QuickLook │ ├── Preview.png │ └── Thumbnail.png │ ├── metadata │ └── version ├── modules ├── custom-target.js ├── custom.js ├── embed-box.js └── index.js ├── package.json ├── scripts ├── build-dist.js ├── build-site.js ├── release.js ├── validate.js └── watch.js ├── test ├── .babelrc ├── examples │ └── custom-target.html ├── package.json ├── test.js ├── test.pug ├── watch.js └── webpack.config.test.js ├── webpack.config.base.js └── webpack.config.site.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | "babel-plugin-transform-decorators-legacy", 4 | "array-includes", 5 | "transform-object-assign", 6 | "transform-array-from", 7 | "transform-proto-to-assign" 8 | ], 9 | "presets": [["es2015", {"modules": false, "loose": true}], "stage-0"] 10 | } 11 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "es6": true, 5 | }, 6 | "extends": "eslint:recommended", 7 | "ecmaVersion": 7, 8 | "globals": { 9 | "ASSET_CDN_URL": null, 10 | "ASSET_PATH": null, 11 | "PROJECT_URL": null, 12 | "process": null, 13 | "VERSION": null 14 | }, 15 | "parser": "babel-eslint", 16 | "plugins": [ 17 | "babel" 18 | ], 19 | "rules": { 20 | "babel/object-curly-spacing": ["warn", "never"], 21 | "array-bracket-spacing": ["warn", "never"], 22 | "arrow-parens": ["warn", "as-needed"], 23 | "arrow-spacing": ["warn", { 24 | "before": true, 25 | "after": true 26 | }], 27 | "block-spacing": ["warn", "always"], 28 | "brace-style": ["warn", "stroustrup", { "allowSingleLine": true }], 29 | "camelcase": "off", 30 | "comma-dangle": ["error", "never"], 31 | "comma-spacing": ["error", { 32 | "before": false, 33 | "after": true 34 | }], 35 | "comma-style": ["warn", "last"], 36 | "computed-property-spacing": ["warn", "never"], 37 | "consistent-this": ["error", "self"], 38 | "consistent-return": "off", 39 | "constructor-super": "error", 40 | "curly": "off", 41 | "default-case": "warn", 42 | "dot-location": ["error", "property"], 43 | "dot-notation": "warn", 44 | "eol-last": "warn", 45 | "eqeqeq": ["error", "allow-null"], 46 | "indent": ["warn", 2, { 47 | "SwitchCase": 1, 48 | "VariableDeclarator": 1 49 | }], 50 | "key-spacing": ["warn", { 51 | "afterColon": true, 52 | "beforeColon": false, 53 | "mode": "strict" 54 | }], 55 | "keyword-spacing": ["warn", { 56 | "after": true, 57 | "before": true 58 | }], 59 | "jsx-quotes": ["warn", "prefer-double"], 60 | "linebreak-style": ["error", "unix"], 61 | "max-nested-callbacks": ["warn", 6], 62 | "new-cap": "error", 63 | "no-cond-assign": ["error", "except-parens"], 64 | "new-parens": "error", 65 | "newline-after-var": "warn", 66 | "no-array-constructor": "error", 67 | "no-caller": "error", 68 | "no-class-assign": "error", 69 | "no-console": "off", 70 | "no-const-assign": "error", 71 | "no-constant-condition": "warn", 72 | "no-continue": "warn", 73 | "no-debugger": "warn", 74 | "no-delete-var": "error", 75 | "no-dupe-class-members": "error", 76 | "no-else-return": "warn", 77 | "no-eval": "error", 78 | "no-extend-native": "error", 79 | "no-extra-bind": "warn", 80 | "no-extra-parens": ["warn", "all"], 81 | "no-floating-decimal": "error", 82 | "no-implied-eval": "error", 83 | "no-inline-comments": "off", 84 | "no-labels": "warn", 85 | "no-label-var": "error", 86 | "no-lone-blocks": "error", 87 | "no-lonely-if": "warn", 88 | "no-loop-func": "error", 89 | "no-mixed-spaces-and-tabs": "warn", 90 | "no-multi-spaces": "warn", 91 | "no-multiple-empty-lines": "warn", 92 | "no-native-reassign": "error", 93 | "no-nested-ternary": "warn", 94 | "no-new": "off", 95 | "no-new-func": "error", 96 | "no-new-object": "error", 97 | "no-new-wrappers": "error", 98 | "no-restricted-syntax": ["error", 99 | "WithStatement" 100 | ], 101 | "no-redeclare": "error", 102 | "no-return-assign": "off", 103 | "no-script-url": "error", 104 | "no-self-compare": "error", 105 | "no-sequences": "error", 106 | "no-shadow-restricted-names": "error", 107 | "no-spaced-func": "warn", 108 | "no-this-before-super": "error", 109 | "no-throw-literal": "error", 110 | "no-undef": "error", 111 | "no-undef-init": "error", 112 | "no-undefined": "error", 113 | "no-unexpected-multiline": "error", 114 | "no-unused-vars": "warn", 115 | "no-use-before-define": "error", 116 | "no-useless-call": "warn", 117 | "no-useless-concat": "warn", 118 | "no-var": "error", 119 | "no-void": "warn", 120 | "no-with": "error", 121 | "object-shorthand": ["warn", "always"], 122 | "one-var": ["warn", { 123 | "let": "never", 124 | "const": "never" 125 | }], 126 | "operator-assignment": ["warn", "always"], 127 | "operator-linebreak": ["warn", "after"], 128 | "padded-blocks": ["warn", "never"], 129 | "prefer-arrow-callback": "warn", 130 | "prefer-const": "error", 131 | "prefer-reflect": "off", 132 | "prefer-spread": "warn", 133 | "quote-props": ["warn", "as-needed"], 134 | "quotes": ["warn", "double"], 135 | "semi": ["error", "never"], 136 | "semi-spacing": ["warn", { 137 | "after": true, 138 | "before": false 139 | }], 140 | "space-before-blocks": ["warn", "always"], 141 | "space-in-parens": ["warn", "never"], 142 | "space-infix-ops": ["warn"], 143 | "space-unary-ops": ["warn"], 144 | "spaced-comment": ["warn", "always"], 145 | "yoda": ["warn", "never", { 146 | "exceptRange": true 147 | }] 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /.github/workflows/semgrep.yml: -------------------------------------------------------------------------------- 1 | 2 | on: 3 | pull_request: {} 4 | workflow_dispatch: {} 5 | push: 6 | branches: 7 | - main 8 | - master 9 | schedule: 10 | - cron: '0 0 * * *' 11 | name: Semgrep config 12 | jobs: 13 | semgrep: 14 | name: semgrep/ci 15 | runs-on: ubuntu-20.04 16 | env: 17 | SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }} 18 | SEMGREP_URL: https://cloudflare.semgrep.dev 19 | SEMGREP_APP_URL: https://cloudflare.semgrep.dev 20 | SEMGREP_VERSION_CHECK_URL: https://cloudflare.semgrep.dev/api/check-version 21 | container: 22 | image: returntocorp/semgrep 23 | steps: 24 | - uses: actions/checkout@v3 25 | - run: semgrep ci 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .sass-cache 2 | .DS_Store 3 | node_modules 4 | bower_components 5 | *.log 6 | site-deploy 7 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | deploy.yaml 2 | circle.yml 3 | webpack.config.js 4 | webpack.site.js 5 | test/ 6 | media/ 7 | scripts/ 8 | examples/ 9 | app/ 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Eager Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # EmbedBox 2 | 3 | [![CircleCI](https://circleci.com/gh/EagerIO/EmbedBox/tree/master.svg?style=svg)](https://circleci.com/gh/EagerIO/EmbedBox/tree/master) 4 | [![npm version](https://badge.fury.io/js/embed-box.svg)](https://badge.fury.io/js/embed-box) 5 | [![Open Source Love](https://badges.frapsoft.com/os/mit/mit.svg?v=102)](https://github.com/ellerbrock/open-source-badge/) 6 | [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/EagerIO/EmbedBox/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22) 7 | 8 | EmbedBox is an open-source UI you can simply drop in to provide instructions for installing your embed code or plugins on every major CMS. 9 | 10 | [Learn how to use EmbedBox in your own project](http://embedbox.io/). 11 | 12 | ## Contributing 13 | 14 | We would love for this to become a project of the community. 15 | Feel free to open an issue, submit a PR or contribute to the docs. 16 | 17 | ### Adding instructions for more CMS platforms 18 | 19 | EmbedBox currently has instructions for all of the most popular CMS platforms, including WordPress, Weebly, Joomla, and Drupal, and we plan to continue to add more over time. 20 | 21 | We’re planning to add more targets over time. You can track our progress in [Project #1](https://github.com/EagerIO/EmbedBox/projects/1). The more CMS instructions we can add, the more useful and powerful EmbedBox will become. Follow [these guidelines](https://github.com/EagerIO/EmbedBox/blob/master/docs/new-targets.md) when contributing docs for new “targets” (what the EmbedBox codebase calls CMS platforms). 22 | 23 | ### Requirements 24 | Node v5.0.0+ 25 | 26 | ### Development 27 | 28 | ```shell 29 | npm install 30 | npm start 31 | ``` 32 | 33 | Then navigate to http://localhost:9000 34 | 35 | For a breakdown of how EmbedBox is built, check out our [design architecture](https://github.com/EagerIO/EmbedBox/blob/master/docs/design-architecture.md) docs. 36 | 37 | ### Testing 38 | 39 | ```shell 40 | cd ./test 41 | npm install 42 | npm test 43 | ``` 44 | 45 | Then navigate to http://localhost:9001 46 | 47 | #### Releases 48 | 49 | EmbedBox uses [semantic versioning](http://semver.org/) 50 | 51 | ```shell 52 | npm run release 1.2.3 53 | git push && git push --tags && npm publish 54 | ``` 55 | 56 | ## Companies using EmbedBox 57 | 58 | - [Eager](https://eager.io) 59 | - [Rakam](https://rakam.io/integrate?part=website) 60 | 61 | Let us know if you’d like your product be added to this list! 62 | 63 | -------------------------------------------------------------------------------- /app/components/application/application.pug: -------------------------------------------------------------------------------- 1 | main( 2 | data-branding=(config.branding ? "visible" : "hidden") 3 | data-flow="column" 4 | data-component="application" 5 | data-target-count=this.targets.length 6 | data-mode=config.mode 7 | role="main") 8 | .surface(data-flow="column") 9 | header.header(role="menubar") 10 | .button( 11 | data-action="previous" 12 | data-ref="previousButton" 13 | tabindex="1" 14 | role="menuitem") 15 | 16 | span.title(data-ref="title") 17 | 18 | .button( 19 | data-action="close" 20 | data-ref="closeModalButton" 21 | tabindex="2" 22 | role="menuitem") 23 | 24 | .content(data-ref="content") 25 | 26 | .branding 27 | a.with-more-icon-after(href=config.projectUrl target="_blank") Powered by EmbedBox 28 | -------------------------------------------------------------------------------- /app/components/application/application.styl: -------------------------------------------------------------------------------- 1 | @import "~styl/colors" 2 | @import "~styl/sizes" 3 | @import "~styl/media-query-variables" 4 | 5 | [data-component="application"] 6 | align-items center 7 | justify-content center 8 | max-height 100% 9 | min-height 100% 10 | 11 | @media (max-height 24em) 12 | justify-content flex-start 13 | 14 | .surface, .branding 15 | width targetInstructionsMaxWidth 16 | max-width 100vw 17 | 18 | .surface 19 | background #fff 20 | min-height 18em 21 | max-width 100vw 22 | flex 1 1 auto 23 | overflow hidden 24 | position relative 25 | z-index 1 // Fix border radius overflow issues. 26 | 27 | .branding 28 | display none 29 | font-size .8em 30 | justify-content flex-end 31 | line-height 3 32 | margin-bottom 1em 33 | 34 | a 35 | color #fff 36 | -webkit-font-smoothing antialiased 37 | text-decoration none 38 | text-shadow 0 1px 2px rgba(#000, .7) 39 | padding 0 .5em 40 | 41 | &:after 42 | font-size 1.4em 43 | 44 | .header 45 | align-items center 46 | box-shadow 0 1px lightLineGrayRGBA 47 | flex 0 0 auto 48 | justify-content space-between 49 | width 100% 50 | max-width 100vw 51 | z-index 1 52 | 53 | > * 54 | display flex 55 | align-items center 56 | 57 | .title 58 | text-align center 59 | line-height 1.4 60 | white-space nowrap 61 | overflow hidden 62 | text-overflow ellipsis 63 | max-width 100% 64 | display inline-block 65 | 66 | @media (max-width 500px) 67 | &[data-title-char-length="long"] 68 | font-size .8em 69 | 70 | &[data-title-char-length="medium"] 71 | font-size .9em 72 | 73 | @media (max-width 400px) 74 | &[data-title-char-length="medium"] 75 | font-size .8em 76 | 77 | &[data-title-char-length="short"] 78 | font-size .9em 79 | 80 | @media (max-width 360px) 81 | &[data-title-char-length="short"] 82 | font-size .8em 83 | 84 | &[data-title-char-length="puny"] 85 | font-size .9em 86 | 87 | @media (max-width 340px) 88 | &[data-title-char-length="puny"] 89 | font-size .8em 90 | 91 | .button[data-action] 92 | appearance none 93 | background inherit 94 | border-radius 0 95 | color inherit 96 | flex 0 0 auto 97 | display flex 98 | height 4em 99 | justify-content center 100 | padding 0 101 | margin 0 102 | width 4em 103 | transition opacity .15s ease 104 | 105 | &:focus:before 106 | display none 107 | 108 | &:hover, &:focus 109 | background lightGrayRGBA 110 | box-shadow none 111 | 112 | > .icon 113 | flex 1 0 auto 114 | width 1em 115 | height 1em 116 | stroke currentColor 117 | 118 | &:not(:hover) .icon 119 | stroke-opacity .5 120 | 121 | .content 122 | transform translate3d(0, 0, 0) 123 | transition transform .2s ease 124 | flex 1 1 auto // Fill center unused space. 125 | 126 | > * 127 | margin 0 128 | flex 1 0 auto 129 | max-width 100vw 130 | width 100% 131 | 132 | &[data-route="home"], &[data-target-count="1"] 133 | 134 | .header [data-action="previous"] 135 | opacity 0 136 | pointer-events none 137 | 138 | &[data-route]:not([data-route="home"]) .content 139 | transform translate3d(-100%, 0, 0) 140 | 141 | &[data-transition-state="transitioned"] [inert] > * 142 | display none 143 | 144 | &[data-mode="modal"] 145 | background rgba(#000, .7) 146 | 147 | @media desktopMinWidthQuery 148 | padding 1.5em 0 149 | 150 | .surface 151 | max-height 38em 152 | border-radius .3125em 153 | 154 | @media desktopMinWidthQuery 155 | box-shadow 0 2px 8px rgba(#000, .4) 156 | 157 | @media mobileMaxWidthQuery 158 | max-height 100vh 159 | width 100% 160 | border-radius 0 161 | 162 | &[data-branding="visible"] 163 | padding-bottom 0 164 | 165 | @media desktopMinWidthQuery 166 | .branding 167 | display flex 168 | 169 | &[data-mode="inline"] 170 | background lightGray 171 | height 100vh 172 | min-height 20em 173 | 174 | .surface 175 | height 100vh 176 | max-height 100vh 177 | 178 | .header [data-action="close"] 179 | opacity 0 180 | pointer-events none 181 | -------------------------------------------------------------------------------- /app/components/base-component.js: -------------------------------------------------------------------------------- 1 | import autobind from "autobind-decorator" 2 | 3 | // Ends with brackets e.g. [data-ref="foo[]"] 4 | const ARRAY_REF_PATTERN = /([a-zA-Z\d]*)(\[?\]?)/ 5 | 6 | export default class BaseComponent { 7 | static template = null; 8 | static stylesheet = null; 9 | static store = null; 10 | 11 | constructor(spec = {}) { 12 | Object.assign(this, { 13 | store: null, 14 | element: null, 15 | refs: {} 16 | }, spec) 17 | 18 | this.appendStylesheet() 19 | } 20 | 21 | appendStylesheet() { 22 | const {stylesheet} = this.constructor 23 | 24 | if (!stylesheet) return 25 | if (!this.store) { 26 | console.error(this) 27 | throw new Error("Component attempted to mount stylesheet without a store reference") 28 | } 29 | 30 | const {element: iframeElement, document: iframeDocument} = this.store.iframe 31 | 32 | const onLoad = () => { 33 | if (iframeDocument.head.contains(this.constructor.styleElement)) return 34 | 35 | // Common style tag has yet to be inserted in iframe. 36 | const styleElement = iframeDocument.createElement("style") 37 | 38 | styleElement.innerHTML = stylesheet 39 | this.constructor.styleElement = iframeDocument.head.appendChild(styleElement) 40 | } 41 | 42 | if (iframeDocument.head) onLoad() 43 | else iframeElement.addEventListener("load", onLoad) 44 | } 45 | 46 | @autobind 47 | asset(path) { 48 | return `${this.store.assetPath}${path}` 49 | } 50 | 51 | autofocus() { 52 | if (this.store.mode === "inline") return 53 | 54 | const focusElement = this.element.querySelector("[autofocus]") 55 | 56 | if (focusElement) focusElement.focus() 57 | } 58 | 59 | // NOTE: Calling `updateRefs` multiple times from different tree depths may 60 | // allow parents to inherit a grandchild. 61 | updateRefs() { 62 | const {refs} = this 63 | 64 | Array 65 | .from(this.element.querySelectorAll("[data-ref]")) 66 | .forEach(element => { 67 | const attribute = element.getAttribute("data-ref") 68 | const [, key, arrayKey] = attribute.match(ARRAY_REF_PATTERN) 69 | 70 | if (arrayKey) { 71 | // Multiple elements 72 | if (!Array.isArray(refs[key])) refs[key] = [] 73 | 74 | refs[key].push(element) 75 | } 76 | else { 77 | // Single element 78 | refs[key] = element 79 | } 80 | 81 | element.removeAttribute("data-ref") 82 | }) 83 | } 84 | 85 | serialize(template, templateVars = {}) { 86 | // `document` is used instead of iframe's document to prevent `instanceof` reference errors. 87 | const serializer = document.createElement("div") 88 | 89 | if (typeof template === "function") { 90 | serializer.innerHTML = template.call(this, { 91 | asset: this.asset, 92 | config: this.store, 93 | label: this.label, 94 | ...templateVars 95 | }) 96 | } 97 | else { 98 | serializer.innerHTML = template 99 | } 100 | 101 | return serializer.firstChild 102 | } 103 | 104 | compileTemplate(templateVars = {}) { 105 | const {template} = this.constructor 106 | 107 | this.element = this.serialize(template, templateVars) 108 | this.updateRefs() 109 | 110 | return this.element 111 | } 112 | 113 | @autobind 114 | label(key) { 115 | const {store} = this 116 | const value = store.labels[key] 117 | 118 | return typeof value === "function" ? value(store) : value 119 | } 120 | 121 | insertBefore(sibling, element) { 122 | element.parentNode.insertBefore(sibling, element) 123 | } 124 | 125 | removeElement(element) { 126 | if (!element || !element.parentNode) return null 127 | 128 | return element.parentNode.removeChild(element) 129 | } 130 | 131 | render() { 132 | return this.compileTemplate() 133 | } 134 | 135 | replaceElement(current, next) { 136 | current.parentNode.insertBefore(next, current) 137 | current.parentNode.removeChild(current) 138 | 139 | next.tabIndex = current.tabIndex 140 | 141 | this.updateRefs() 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /app/components/base-screenshot/arrow-bottom-left.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/components/base-screenshot/arrow-bottom-right.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/components/base-screenshot/arrow-top-left.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/components/base-screenshot/arrow-top-right.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/components/base-screenshot/base-screenshot.pug: -------------------------------------------------------------------------------- 1 | figure(data-component="screenshot") 2 | iframe( 3 | frameBorder="0" 4 | srcdoc="
" 5 | src="about:blank") 6 | -------------------------------------------------------------------------------- /app/components/base-screenshot/index.js: -------------------------------------------------------------------------------- 1 | import iframeTemplate from "./base-screenshot.pug" 2 | import iframeStylesheet from "./screenshot-iframe.styl" 3 | 4 | import autobind from "autobind-decorator" 5 | import BaseComponent from "components/base-component" 6 | import createStylesheetTemplate from "lib/create-stylesheet-template" 7 | 8 | const toPrecision = (number, precision = 5) => parseFloat(number.toPrecision(precision)) 9 | 10 | export default class BaseScreenshot { 11 | static iframeTemplate = iframeTemplate; 12 | static iframeStylesheet = iframeStylesheet; 13 | 14 | serialize = BaseComponent.prototype.serialize; 15 | constructor(spec) { 16 | Object.assign(this, spec) 17 | } 18 | 19 | @autobind 20 | setScale() { 21 | const iframeDocument = this.iframe.contentDocument 22 | const {getComputedStyle} = iframeDocument.defaultView 23 | const {width: widthStyle, height: heightStyle} = getComputedStyle(iframeDocument.body) 24 | const width = parseInt(widthStyle, 10) 25 | const height = parseInt(heightStyle, 10) 26 | const intrinsicRatio = toPrecision(height / width) 27 | const paddingBottom = `${intrinsicRatio * 100}%` 28 | 29 | this.iframe.setAttribute("width", width) 30 | this.iframe.setAttribute("height", height) 31 | this.element.style.paddingBottom = paddingBottom 32 | 33 | requestAnimationFrame(() => { 34 | const scale = toPrecision(this.element.clientWidth / width) 35 | 36 | this.iframe.style.transform = `scale(${scale})` 37 | this.element.setAttribute("data-render-state", "scaled") 38 | }) 39 | } 40 | 41 | applyTheme() { 42 | const {iframeStylesheet, stylesheet} = this.constructor 43 | const iframeDocument = this.iframe.contentDocument 44 | const iframeStyle = iframeDocument.createElement("style") 45 | const style = iframeDocument.createElement("style") 46 | 47 | const stylesheetTemplate = createStylesheetTemplate(this.store.theme) 48 | 49 | const themeStyles = stylesheetTemplate` 50 | .screenshot .focal-point { 51 | box-shadow: 0 0 0 4px ${"screenshotAnnotationColor"} 52 | } 53 | 54 | .screenshot a.focal-point { 55 | background-color: ${"screenshotAnnotationColor"} 56 | } 57 | 58 | .screenshot [data-arrow]::before, 59 | .screenshot [data-arrow]::after { 60 | color: ${"screenshotAnnotationColor"} 61 | } 62 | ` 63 | 64 | iframeStyle.innerHTML = [iframeStylesheet, themeStyles].join(" ") 65 | iframeDocument.head.appendChild(iframeStyle) 66 | 67 | style.innerHTML = stylesheet 68 | iframeDocument.head.appendChild(style) 69 | } 70 | 71 | render(target) { 72 | const {iframeTemplate, template} = this.constructor 73 | const element = this.element = this.serialize(iframeTemplate) 74 | 75 | this.iframe = element.querySelector("iframe") 76 | 77 | this.iframe.onload = () => { 78 | this.applyTheme() 79 | 80 | const iframeDocument = this.iframe.contentDocument 81 | const element = this.serialize.call(target, template) 82 | 83 | iframeDocument.body.appendChild(element) 84 | 85 | requestAnimationFrame(() => { 86 | if (this.componentDidMount) this.componentDidMount(target) 87 | this.setScale() 88 | }) 89 | 90 | window.addEventListener("resize", () => { 91 | this.setScale() 92 | }) 93 | } 94 | 95 | return this.element 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /app/components/base-screenshot/mixin-annotation-arrow.pug: -------------------------------------------------------------------------------- 1 | mixin annotation-arrow(direction) 2 | - var firstDirection = direction.substr(0, 1) 3 | - var isNS = ["n", "s"].indexOf(firstDirection) !== -1 4 | - var viewBox = isNS ? "0 0 83 114" : "0 0 127 73" 5 | - var d = isNS ? "M39.3 5.4L0.9 0C0.3-0.1-0.1 0.3 0 0.9L9.1 37.8C9.2 38.4 9.7 38.5 10.1 38.1 10.1 38.1 18 29.8 19.8 27.9 19.9 27.7 20.1 27.4 20.5 27.4 20.9 27.3 21.3 27.4 21.4 27.5 68.7 64.9 76 103.8 77.1 109.6 78.2 115.4 84 114.4 82.9 108.6 81.8 102.8 75.7 53.3 30 17.7 29.9 17.6 29.6 17.4 29.6 17.1 29.6 16.9 29.9 16.6 30 16.5L39.6 6.4C40.1 5.9 39.9 5.5 39.3 5.4Z" : "M37.3 0.7C37.4 0.1 37.1-0.1 36.5 0.1L0.5 14.6C-0.1 14.9-0.2 15.4 0.3 15.8L26.5 43.2C27 43.7 27.4 43.6 27.6 43 27.6 43 30.2 31.8 30.8 29.3 30.9 29.1 30.9 28.7 31.2 28.5 31.5 28.3 31.9 28.1 32 28.2 91.7 36.9 117.5 67 121.4 71.4 125.2 75.9 129.7 72.1 125.8 67.6 122 63.1 92 23.4 34.6 15.4 34.5 15.4 34.1 15.3 33.9 15.1 33.8 14.9 34 14.5 34 14.3 35.2 9.4 37.3 0.7 37.3 0.7Z" 6 | 7 | - var transform = attributes.transform || "" 8 | 9 | if ["ne", "en"].indexOf(direction) !== -1 10 | - transform += " scale(-1, 1)" 11 | else if ["se", "es"].indexOf(direction) !== -1 12 | - transform += " scale(-1, -1)" 13 | else if ["sw", "ws"].indexOf(direction) !== -1 14 | - transform += " scale(1, -1)" 15 | 16 | if transform.length === 0 17 | - transform = "none" 18 | 19 | //- HTML necessary to workaround IE SVG scaling issues 20 | div(annotation-arrow data-svg-view-box=viewBox style=attributes.style) 21 | div 22 | svg(version="1.1" viewBox=viewBox style={transform: transform}) 23 | path(d=d) 24 | -------------------------------------------------------------------------------- /app/components/base-screenshot/screenshot-iframe.styl: -------------------------------------------------------------------------------- 1 | @import "~normalize.css/normalize.css" 2 | @import "~styl/reset" 3 | @import "~styl/box-sizing-border-box-all" 4 | @import "~styl/colors" 5 | @import "~highlight.js/styles/vs.css" 6 | 7 | baseFontSize = 16px 8 | 9 | html, body 10 | width 100% 11 | height 100% 12 | 13 | body 14 | font-size baseFontSize 15 | margin 0 16 | overflow hidden 17 | 18 | div, footer, header, main, section 19 | display flex 20 | 21 | [data-flow="column"] 22 | flex-flow column nowrap 23 | 24 | .screenshot 25 | flex-flow column 26 | position relative 27 | width 100% 28 | 29 | .arrow-parent, .relative-arrow 30 | position relative 31 | z-index 10 32 | 33 | > pre 34 | background lightGrayRGBA 35 | margin 0 36 | padding 1em 37 | 38 | .focal-point 39 | color #000 40 | font-weight bold 41 | padding .3em 42 | 43 | [data-arrow] 44 | align-items center 45 | display inline-flex 46 | 47 | &::before, &::after 48 | display inline-block 49 | font-family sans-serif 50 | font-weight normal 51 | font-size 4.4em 52 | line-height baseFontSize 53 | opacity .9 54 | text-shadow 0 1px 0 rgba(0,0,0,0.3) 55 | 56 | [data-arrow="left"]::before 57 | content "→" 58 | 59 | [data-arrow="right"]::after 60 | content "←" 61 | 62 | [data-arrow="above"]::before 63 | content "↓" 64 | right 0 !important 65 | top -0.6em 66 | 67 | .relative-arrow 68 | &::before, &::after 69 | position absolute 70 | 71 | .relative-arrow::before 72 | right 100% 73 | 74 | .relative-arrow::after 75 | left 100% 76 | 77 | -------------------------------------------------------------------------------- /app/components/base-target/after-content.pug: -------------------------------------------------------------------------------- 1 | if config.afterContent || this.config.afterContent 2 | div(data-content-slot="after") 3 | p!= config.afterContent 4 | p!= this.config.afterContent 5 | -------------------------------------------------------------------------------- /app/components/base-target/base-target.pug: -------------------------------------------------------------------------------- 1 | section 2 | != this.renderTitle() 3 | != this.renderBeforeContent() 4 | 5 | .steps-mount(data-ref="stepsMount") 6 | 7 | != this.renderAfterContent() 8 | -------------------------------------------------------------------------------- /app/components/base-target/base-target.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/components/base-target/before-content.pug: -------------------------------------------------------------------------------- 1 | if config.beforeContent || this.config.beforeContent 2 | div(data-content-slot="before") 3 | p!= config.beforeContent 4 | p!= this.config.beforeContent 5 | -------------------------------------------------------------------------------- /app/components/base-target/download-link.pug: -------------------------------------------------------------------------------- 1 | h2 2 | a.more(href=this.pluginURL download target="_blank")= this.downloadLabel 3 | div= this.autoDownloadLabel 4 | -------------------------------------------------------------------------------- /app/components/base-target/title.pug: -------------------------------------------------------------------------------- 1 | header.target-title(data-flow="column") 2 | .icon!= this.icon 3 | 4 | h1!= this.title 5 | 6 | if this.versionIDs.length > 1 7 | .versions 8 | .label!= this.instructionsLabel 9 | 10 | select(data-ref="versionSelector") 11 | each versionID in this.versionIDs 12 | option(selected=(versionID === this.versionID))= versionID 13 | -------------------------------------------------------------------------------- /app/components/icons/clear.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/components/icons/close.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/components/icons/collapse.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/components/icons/copy.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/components/icons/index.js: -------------------------------------------------------------------------------- 1 | import BaseComponent from "components/base-component" 2 | 3 | export const svgToComponent = template => { 4 | return class Icon extends BaseComponent { 5 | static template = template; 6 | 7 | constructor(attributes = {}) { 8 | super() 9 | 10 | this.attributes = {class: "icon", ...attributes} 11 | } 12 | 13 | render() { 14 | const element = this.compileTemplate() 15 | 16 | Object 17 | .keys(this.attributes) 18 | .forEach(key => element.setAttribute(key, this.attributes[key])) 19 | 20 | return element 21 | } 22 | } 23 | } 24 | 25 | import closeSVG from "./close.svg" 26 | export const close = svgToComponent(closeSVG) 27 | 28 | import previousSVG from "./previous.svg" 29 | export const previous = svgToComponent(previousSVG) 30 | 31 | import nextSVG from "./next.svg" 32 | export const next = svgToComponent(nextSVG) 33 | 34 | import searchSVG from "./search.svg" 35 | export const search = svgToComponent(searchSVG) 36 | 37 | import clearSVG from "./clear.svg" 38 | export const clear = svgToComponent(clearSVG) 39 | 40 | import copySVG from "./copy.svg" 41 | export const copy = svgToComponent(copySVG) 42 | 43 | import collapseSVG from "./collapse.svg" 44 | export const collapse = svgToComponent(collapseSVG) 45 | -------------------------------------------------------------------------------- /app/components/icons/next.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/components/icons/previous.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/components/icons/search.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/components/target-search/target-search.pug: -------------------------------------------------------------------------------- 1 | section(data-flow="column" data-component="target-search" data-event-receiver) 2 | header.header(data-flow="column") 3 | label(for="search-input")= label("searchHeader") 4 | .input-wrapper(data-ref="inputWrapper") 5 | input#search-input.search( 6 | data-ref="search" 7 | placeholder=label("searchPlaceholder") 8 | spellcheck="false" 9 | tabindex="3" 10 | type="text") 11 | .search-clear( 12 | data-ref="searchClear" 13 | tabindex="3") 14 | 15 | .entries(data-flow="column" data-ref="entriesContainer") 16 | -------------------------------------------------------------------------------- /app/components/target-wrapper/index.js: -------------------------------------------------------------------------------- 1 | import template from "./target-wrapper.pug" 2 | import stylesheet from "./target-wrapper.styl" 3 | 4 | import BaseComponent from "components/base-component" 5 | 6 | export default class TargetWrapper extends BaseComponent { 7 | static template = template; 8 | static stylesheet = stylesheet; 9 | 10 | render() { 11 | this.compileTemplate() 12 | 13 | const target = this.target.render() 14 | const {targetMount} = this.refs 15 | 16 | this.replaceElement(targetMount, target) 17 | 18 | return this.element 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /app/components/target-wrapper/screenshot.styl: -------------------------------------------------------------------------------- 1 | @import "~styl/colors" 2 | 3 | figure 4 | margin 2em 0 5 | position relative 6 | 7 | img, &[data-component="screenshot"] 8 | background #fff 9 | display block 10 | max-width 100% 11 | 12 | &[data-component="screenshot"] 13 | height 0 14 | overflow hidden 15 | // padding-bottom set by JS 16 | padding-left 0 17 | padding-right 0 18 | padding-top 0 19 | position relative 20 | width 100% 21 | 22 | iframe 23 | border 0 24 | left 0 25 | opacity 0 26 | position absolute 27 | top 0 28 | transform-origin 0 0 29 | 30 | &[data-render-state="scaled"] iframe 31 | opacity 1 32 | 33 | &::after 34 | content "" 35 | position absolute 36 | display block 37 | cursor default 38 | border 1px solid lightLineGrayRGBA 39 | z-index 1 40 | top 0 41 | right 0 42 | bottom 0 43 | left 0 44 | 45 | [data-component="application"][data-mode="modal"] & 46 | border-left 0 47 | border-right 0 48 | 49 | @media mobileMaxWidthQuery 50 | border 1px solid lightLineGrayRGBA 51 | 52 | @media smallerThanTargetInstructionsMaxWidthQuery 53 | border-left 0 54 | border-right 0 55 | 56 | @media smallerThanTargetInstructionsMaxWidthQuery 57 | border-left 0 58 | border-right 0 59 | 60 | [annotation-arrow] 61 | position absolute 62 | 63 | > div 64 | position absolute 65 | top 0 66 | left 0 67 | height 0 68 | width 100% 69 | 70 | svg 71 | position absolute 72 | top 0 73 | left 0 74 | width 100% 75 | height 100% 76 | 77 | &[data-svg-view-box="0 0 83 114"] > div 78 | padding-bottom 137.35% 79 | 80 | &[data-svg-view-box="0 0 127 73"] > div 81 | padding-bottom 57.48% 82 | -------------------------------------------------------------------------------- /app/components/target-wrapper/target-wrapper.pug: -------------------------------------------------------------------------------- 1 | section(data-flow="column" data-component="target-wrapper") 2 | .target-mount(data-ref="targetMount" tabindex="3") 3 | 4 | -------------------------------------------------------------------------------- /app/embed-box.styl: -------------------------------------------------------------------------------- 1 | @import "./styl/media-query-variables" 2 | 3 | .embed-box 4 | display block 5 | 6 | &[data-mode="inline"] 7 | width 100% 8 | height 576px 9 | min-height 320px 10 | max-height 100vh 11 | 12 | &[data-mode="modal"] 13 | position fixed !important 14 | z-index 100000 !important 15 | top 0 !important 16 | right 0 !important 17 | bottom 0 !important 18 | left 0 !important 19 | height 100% !important 20 | width 100% !important 21 | max-height 100vh !important 22 | max-width 100vw !important 23 | transition opacity .1s linear !important 24 | opacity 0 25 | 26 | @media mobileMaxWidthQuery 27 | position absolute !important 28 | 29 | body[data-embed-box-scroll-state="locked"] 30 | overflow hidden !important 31 | 32 | @media mobileMaxWidthQuery 33 | body, html 34 | &[data-embed-box-scroll-state="locked"] 35 | position fixed !important 36 | overflow hidden !important 37 | top 0 !important 38 | right 0 !important 39 | bottom 0 !important 40 | left 0 !important 41 | 42 | .embed-box-download-iframe 43 | position fixed 44 | z-index -99999 45 | visibility hidden 46 | width 1px 47 | height 1px 48 | 49 | [data-embed-box-scroll-state] 50 | height 100% 51 | -------------------------------------------------------------------------------- /app/iframe.styl: -------------------------------------------------------------------------------- 1 | @import "shared" 2 | 3 | html, body 4 | overflow hidden 5 | 6 | html 7 | background transparent 8 | 9 | main 10 | height 100% 11 | overflow hidden 12 | 13 | body 14 | background transparent 15 | cursor default 16 | user-select none 17 | -------------------------------------------------------------------------------- /app/lib/create-stylesheet-template.js: -------------------------------------------------------------------------------- 1 | export default function createStylesheetTemplate(definitions) { 2 | return function stylesheetTemplate(strings, ...values) { 3 | const merged = strings.slice() 4 | let offset = 0 5 | 6 | for (let i = 0; i < merged.length; i++) { 7 | if (i === values.length) break 8 | 9 | offset++ 10 | const value = `${definitions[values[i] || "inherit"]} !important;` 11 | 12 | merged.splice(i + offset, 0, value) 13 | } 14 | 15 | return merged.join("") 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /app/lib/create-theme-stylesheet.js: -------------------------------------------------------------------------------- 1 | import createStylesheetTemplate from "lib/create-stylesheet-template" 2 | 3 | export default function createThemeStylesheet(theme) { 4 | const stylesheetTemplate = createStylesheetTemplate(theme) 5 | 6 | return stylesheetTemplate` 7 | [data-component="application"] .surface { 8 | background-color: ${"backgroundColor"} 9 | color: ${"textColor"} 10 | } 11 | 12 | [data-component$="-target"] .copy-container[collapsed] button.collapse { 13 | background-color: ${"backgroundColor"} 14 | } 15 | 16 | .surface a, .accent-color { 17 | color: ${"accentColor"} 18 | } 19 | 20 | .button.primary, button.primary, 21 | [data-component="target-search"] .entries .entry[data-selected], 22 | [data-component="target-search"] .entries .entry:active, 23 | [data-component="application"][is-touch-device="true"] [data-component="target-search"] .entries .entry:hover, 24 | .accent-background-color { 25 | background: ${"accentColor"} 26 | } 27 | 28 | .target-instructions .steps li::before { 29 | background: ${"stepNumberColor"} 30 | } 31 | 32 | .target-instructions figure [annotation-arrow] svg { 33 | fill: ${"screenshotAnnotationColor"} 34 | } 35 | ` 36 | } 37 | -------------------------------------------------------------------------------- /app/lib/custom-event.js: -------------------------------------------------------------------------------- 1 | export default function polyfillCustomEvent({document: $document, window: $window}) { 2 | let supported = true 3 | 4 | try { 5 | // IE10 will fail to construct a CustomEvent 6 | new $window.CustomEvent() 7 | } 8 | catch (e) { 9 | supported = false 10 | } 11 | 12 | if (supported) { 13 | $window.PolyFilledCustomEvent = $window.CustomEvent 14 | return 15 | } 16 | 17 | function PolyFilledCustomEvent(event, {bubbles = false, cancelable = false, detail} = {}) { 18 | const shimEvent = $document.createEvent("CustomEvent") 19 | 20 | shimEvent.initCustomEvent(event, bubbles, cancelable, detail) 21 | 22 | return shimEvent 23 | } 24 | 25 | PolyFilledCustomEvent.prototype = $window.Event.prototype 26 | 27 | $window.PolyFilledCustomEvent = PolyFilledCustomEvent 28 | } 29 | -------------------------------------------------------------------------------- /app/lib/key-map.js: -------------------------------------------------------------------------------- 1 | export default { 2 | backspace: 8, 3 | enter: 13, 4 | esc: 27, 5 | spacebar: 32, 6 | left: 37, 7 | up: 38, 8 | right: 39, 9 | down: 40 10 | } 11 | -------------------------------------------------------------------------------- /app/lib/request-animation-frame.js: -------------------------------------------------------------------------------- 1 | export default function polyfillRequestAnimationFrame(window) { 2 | let lastTime = 0 3 | 4 | window.requestAnimationFrame = window.msRequestAnimationFrame 5 | window.cancelAnimationFrame = window.msCancelAnimationFrame || window.msCancelRequestAnimationFrame 6 | 7 | if (!window.requestAnimationFrame) { 8 | window.requestAnimationFrame = function(callback) { 9 | const currTime = new Date().getTime() 10 | const timeToCall = Math.max(0, 16 - (currTime - lastTime)) 11 | const id = window.setTimeout(() => callback(currTime + timeToCall), timeToCall) 12 | 13 | lastTime = currTime + timeToCall 14 | 15 | return id 16 | } 17 | } 18 | 19 | if (!window.cancelAnimationFrame) { 20 | window.cancelAnimationFrame = clearTimeout 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /app/lib/routing.js: -------------------------------------------------------------------------------- 1 | const ROUTE_PREFIX = "#!/embed/" 2 | 3 | export function getRoute() { 4 | return window.location.hash.split(ROUTE_PREFIX)[1] || null 5 | } 6 | 7 | export function setRoute(route = "") { 8 | const {pathname} = window.location 9 | 10 | if (route === "" && window.history.pushState && pathname !== "srcdoc") { 11 | window.history.pushState("", "", pathname) 12 | 13 | return 14 | } 15 | 16 | window.location.hash = ROUTE_PREFIX + route 17 | } 18 | -------------------------------------------------------------------------------- /app/lib/store.js: -------------------------------------------------------------------------------- 1 | const DEFAULT_THEME = { 2 | accentColor: "#2d88f3", 3 | backgroundColor: "#ffffff", 4 | screenshotAnnotationColor: "#fde757", 5 | textColor: "#000000" 6 | } 7 | 8 | const get = (value, fallback) => typeof value !== "undefined" ? value : fallback 9 | 10 | export function createStore(spec = {}) { 11 | const iframe = document.createElement("iframe") 12 | const {autoDownload = true, labels = {}} = spec 13 | 14 | const theme = {...DEFAULT_THEME, ...spec.theme} 15 | 16 | if (!theme.stepNumberColor) theme.stepNumberColor = theme.accentColor 17 | 18 | return { 19 | assetPath: get(spec.assetPath, ASSET_PATH), 20 | name: get(spec.name, "a plugin"), 21 | autoDownload, 22 | 23 | branding: get(spec.branding, true), 24 | 25 | beforeContent: get(spec.beforeContent, ""), 26 | afterContent: get(spec.afterContent, ""), 27 | 28 | embedCode: get(spec.embedCode, ""), 29 | 30 | fallbackID: get(spec.fallbackID, "generic"), 31 | 32 | iframe: { 33 | element: iframe, 34 | get document() { 35 | return iframe.contentDocument 36 | }, 37 | get window() { 38 | return iframe.contentWindow 39 | } 40 | }, 41 | 42 | insertInHead: get(spec.insertInHead, false), 43 | 44 | labels: { 45 | searchHeader: "Select the type of website you have.", 46 | searchPlaceholder: "Search...", 47 | clickHint: "Click to view instructions", 48 | clickHintShort: "Click to view", 49 | submitHint: "Press ENTER to view instructions", 50 | submitHintShort: "Press ENTER", 51 | title: config => `Add ${config.name} to your site`, 52 | ...labels 53 | }, 54 | 55 | route: "home", 56 | routing: get(spec.routing, false), 57 | projectUrl: PROJECT_URL, 58 | 59 | scrollIntoView: get(spec.scrollIntoView, true), 60 | 61 | theme 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /app/lib/to-dash-case.js: -------------------------------------------------------------------------------- 1 | const PATTERN = /([a-z])([A-Z])/g 2 | 3 | export default function toDashCase(string = "") { 4 | return string.replace(PATTERN, "$1-$2").toLowerCase() 5 | } 6 | -------------------------------------------------------------------------------- /app/shared.styl: -------------------------------------------------------------------------------- 1 | @import "styl/reset" 2 | @import "styl/box-sizing-border-box-all" 3 | @import "styl/body-typography" 4 | @import "styl/buttons" 5 | @import "styl/more-links-and-buttons" 6 | @import "styl/media-query-variables" 7 | @import "styl/colors" 8 | @import "styl/loading-dots" 9 | 10 | html, body 11 | height 100% 12 | 13 | body 14 | margin 0 15 | 16 | div, footer, header, main, section 17 | display flex 18 | 19 | [data-flow="column"] 20 | flex-flow column nowrap 21 | 22 | [data-action] 23 | cursor pointer 24 | 25 | [data-action], [tabindex] 26 | -webkit-tap-highlight-color transparent 27 | 28 | [data-selectable], [contenteditable] 29 | cursor text 30 | user-select text 31 | -------------------------------------------------------------------------------- /app/site/assets/customize-feature.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/embed-box/14e8488bf334bb34038a4129d39d6ecd32078179/app/site/assets/customize-feature.png -------------------------------------------------------------------------------- /app/site/assets/documentation-feature.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/embed-box/14e8488bf334bb34038a4129d39d6ecd32078179/app/site/assets/documentation-feature.png -------------------------------------------------------------------------------- /app/site/assets/dotted.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/embed-box/14e8488bf334bb34038a4129d39d6ecd32078179/app/site/assets/dotted.png -------------------------------------------------------------------------------- /app/site/assets/eager-logo.svg: -------------------------------------------------------------------------------- 1 | 14 | -------------------------------------------------------------------------------- /app/site/assets/examples/drupal-plugin.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/embed-box/14e8488bf334bb34038a4129d39d6ecd32078179/app/site/assets/examples/drupal-plugin.zip -------------------------------------------------------------------------------- /app/site/assets/examples/joomla-plugin.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/embed-box/14e8488bf334bb34038a4129d39d6ecd32078179/app/site/assets/examples/joomla-plugin.zip -------------------------------------------------------------------------------- /app/site/assets/examples/library.js: -------------------------------------------------------------------------------- 1 | console.log("Mama always said life was like a box of chocolates. You never know what you're gonna get. - Forrest Gump") 2 | -------------------------------------------------------------------------------- /app/site/assets/examples/library.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/embed-box/14e8488bf334bb34038a4129d39d6ecd32078179/app/site/assets/examples/library.zip -------------------------------------------------------------------------------- /app/site/assets/examples/weebly-library.js: -------------------------------------------------------------------------------- 1 | console.log("There's no better feeling in the world than a warm pizza box on your lap. - Kevin James") 2 | -------------------------------------------------------------------------------- /app/site/assets/examples/wordpress-plugin.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/embed-box/14e8488bf334bb34038a4129d39d6ecd32078179/app/site/assets/examples/wordpress-plugin.zip -------------------------------------------------------------------------------- /app/site/assets/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/embed-box/14e8488bf334bb34038a4129d39d6ecd32078179/app/site/assets/favicon.png -------------------------------------------------------------------------------- /app/site/assets/got-plugins-feature.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/embed-box/14e8488bf334bb34038a4129d39d6ecd32078179/app/site/assets/got-plugins-feature.png -------------------------------------------------------------------------------- /app/site/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/embed-box/14e8488bf334bb34038a4129d39d6ecd32078179/app/site/assets/logo.png -------------------------------------------------------------------------------- /app/site/examples/advanced.md: -------------------------------------------------------------------------------- 1 | ```javascript 2 | new EmbedBox({ 3 | name: "Example Plugin", 4 | embedCode: "", 5 | targets: { 6 | weebly: { 7 | embedCode: "" 8 | } 9 | } 10 | }) 11 | ``` 12 | -------------------------------------------------------------------------------- /app/site/examples/asset-path.md: -------------------------------------------------------------------------------- 1 | ```javascript 2 | new EmbedBox({ 3 | assetPath: "/assets/images/embed-box" 4 | }) 5 | ``` 6 | -------------------------------------------------------------------------------- /app/site/examples/auto-show.md: -------------------------------------------------------------------------------- 1 | ```javascript 2 | var embedBox = new EmbedBox({ 3 | autoShow: false, 4 | embedCode: "" 5 | }) 6 | 7 | embedBox.show() 8 | 9 | setTimeout(function () { 10 | embedBox.destroy() 11 | }, 5000) 12 | ``` 13 | -------------------------------------------------------------------------------- /app/site/examples/basic-node.md: -------------------------------------------------------------------------------- 1 | ```javascript 2 | import EmbedBox from "embed-box" 3 | 4 | new EmbedBox({ 5 | name: "Example Plugin", 6 | embedCode: "" 7 | }) 8 | ``` 9 | -------------------------------------------------------------------------------- /app/site/examples/basic-web.md: -------------------------------------------------------------------------------- 1 | ```javascript 2 | new EmbedBox({ 3 | name: "Example Plugin", 4 | embedCode: "" + 5 | "\n" + 6 | "" 12 | }) 13 | ``` 14 | -------------------------------------------------------------------------------- /app/site/examples/basic.md: -------------------------------------------------------------------------------- 1 | ```javascript 2 | new EmbedBox({ 3 | name: "Example Plugin", 4 | embedCode: "" 5 | }) 6 | ``` 7 | -------------------------------------------------------------------------------- /app/site/examples/container-element.md: -------------------------------------------------------------------------------- 1 | ```javascript 2 | new EmbedBox({ 3 | container: document.querySelector(".my-element") 4 | }) 5 | ``` 6 | -------------------------------------------------------------------------------- /app/site/examples/container-selector.md: -------------------------------------------------------------------------------- 1 | ```javascript 2 | new EmbedBox({ 3 | container: ".my-element" 4 | }) 5 | ``` 6 | -------------------------------------------------------------------------------- /app/site/examples/content-slots.md: -------------------------------------------------------------------------------- 1 | ```javascript 2 | new EmbedBox({ 3 | name: "FooBar", 4 | embedCode: "", 5 | beforeContent: "Having some trouble? " + 6 | "Call us at (555)-123-4567", 7 | afterContent: "You should receive an email with your account password.", 8 | targets: { 9 | wordpress: { 10 | beforeContent: "FooBar works best with WordPress 4.0 or higher." 11 | } 12 | } 13 | }) 14 | ``` 15 | -------------------------------------------------------------------------------- /app/site/examples/custom-install.md: -------------------------------------------------------------------------------- 1 | ```html 2 | 3 | ``` 4 | -------------------------------------------------------------------------------- /app/site/examples/custom-stylesheet.md: -------------------------------------------------------------------------------- 1 | ```javascript 2 | new EmbedBox({ 3 | embedCode: "", 4 | name: "Example Stylesheet App", 5 | style: "" + 6 | ".header .title {" + 7 | " color: hotpink;" + 8 | " text-shadow: 0 0 4px pink;" + 9 | "}" 10 | }) 11 | ``` 12 | -------------------------------------------------------------------------------- /app/site/examples/custom-target.md: -------------------------------------------------------------------------------- 1 | ```javascript 2 | var CustomTarget = EmbedBoxCustomTarget.extend({ 3 | id: "custom-test", 4 | label: "Custom Target", 5 | templateVars: { 6 | registerURL: "http://example.com/register" 7 | }, 8 | template: function(vars) { 9 | return "" + 10 | "
    " + 11 | "
  1. " + 12 | "

    " + 13 | " Register an account before installing." + 14 | "

    " + 15 | "
  2. " + 16 | "
" 17 | } 18 | }) 19 | 20 | new EmbedBox({ 21 | embedCode: "", 22 | customTargets: [CustomTarget] 23 | }) 24 | ``` 25 | -------------------------------------------------------------------------------- /app/site/examples/custom-theme.md: -------------------------------------------------------------------------------- 1 | ```javascript 2 | new EmbedBox({ 3 | embedCode: "", 4 | name: "Example Theme App", 5 | theme: { 6 | accentColor: "#665292", 7 | backgroundColor: "#e0e0e0", 8 | screenshotAnnotationColor: "#665292", 9 | stepNumberColor: "#665292", 10 | textColor: "#444444" 11 | } 12 | }) 13 | ``` 14 | -------------------------------------------------------------------------------- /app/site/examples/events.md: -------------------------------------------------------------------------------- 1 | ```javascript 2 | var embedBox = new EmbedBox({ 3 | embedCode: "", 4 | events: { 5 | onLoad: function() { 6 | console.log(this) // EmbedBox instance 7 | alert("EmbedBox loaded!") 8 | } 9 | } 10 | }) 11 | ``` 12 | -------------------------------------------------------------------------------- /app/site/examples/get-target-ids.md: -------------------------------------------------------------------------------- 1 | ```javascript 2 | EmbedBox.getTargetIDs() 3 | 4 | // {{TARGET_IDS}} 5 | ``` 6 | -------------------------------------------------------------------------------- /app/site/examples/initial-target.md: -------------------------------------------------------------------------------- 1 | ```javascript 2 | new EmbedBox({ 3 | embedCode: "", 4 | initialTarget: "wordpress" 5 | }) 6 | ``` 7 | -------------------------------------------------------------------------------- /app/site/examples/install-node.md: -------------------------------------------------------------------------------- 1 | ```bash 2 | npm install --save embed-box 3 | ``` 4 | -------------------------------------------------------------------------------- /app/site/examples/install-web.md: -------------------------------------------------------------------------------- 1 | ```html 2 | 3 | ``` 4 | -------------------------------------------------------------------------------- /app/site/examples/labels.md: -------------------------------------------------------------------------------- 1 | ```javascript 2 | new EmbedBox({ 3 | name: "Acme plugin", 4 | embedCode: "", 5 | labels: { 6 | title: function(config) { return config.name + " install guide" }, 7 | searchHeader: "Press or enter the type of website you have.", 8 | searchPlaceholder: "Filter..." 9 | } 10 | }) 11 | ``` 12 | -------------------------------------------------------------------------------- /app/site/examples/ordering.md: -------------------------------------------------------------------------------- 1 | ```javascript 2 | new EmbedBox({ 3 | embedCode: "", 4 | targets: { 5 | wordpress: { 6 | priority: 1 7 | }, 8 | drupal: { 9 | priority: 2 10 | }, 11 | weebly: { 12 | priority: 3 13 | }, 14 | joomla: { 15 | priority: -1 16 | } 17 | } 18 | }) 19 | ``` 20 | -------------------------------------------------------------------------------- /app/site/examples/plugin-url.md: -------------------------------------------------------------------------------- 1 | ```javascript 2 | new EmbedBox({ 3 | embedCode: "", 4 | targets: { 5 | wordpress: { 6 | pluginURL: "{{PROJECT_URL}}/examples/wordpress-plugin.zip" 7 | }, 8 | drupal: { 9 | pluginURL: "{{PROJECT_URL}}/examples/drupal-plugin.zip" 10 | }, 11 | joomla: { 12 | pluginURL: "{{PROJECT_URL}}/examples/joomla-plugin.zip" 13 | } 14 | } 15 | }) 16 | ``` 17 | -------------------------------------------------------------------------------- /app/site/examples/routing.md: -------------------------------------------------------------------------------- 1 | ```javascript 2 | window.location.hash = "!/embed/drupal" 3 | 4 | new EmbedBox({ 5 | routing: true, 6 | embedCode: "" 7 | }) 8 | ``` 9 | -------------------------------------------------------------------------------- /app/site/globals/embed-box-custom-target.js: -------------------------------------------------------------------------------- 1 | import EmbedBoxCustomTarget from "../../../modules/custom-target" 2 | 3 | Object.assign(window, {EmbedBoxCustomTarget}) 4 | -------------------------------------------------------------------------------- /app/site/globals/embed-box-custom.js: -------------------------------------------------------------------------------- 1 | import EmbedBoxCustom from "../../../modules/custom" 2 | 3 | Object.assign(window, {EmbedBoxCustom}) 4 | -------------------------------------------------------------------------------- /app/site/globals/embed-box.js: -------------------------------------------------------------------------------- 1 | import EmbedBox from "../../../modules/embed-box" 2 | 3 | Object.assign(window, {EmbedBox}) 4 | -------------------------------------------------------------------------------- /app/site/index.js: -------------------------------------------------------------------------------- 1 | import "./site.styl" 2 | 3 | import {runDemo} from "site/lib/user-simulator" 4 | import loadScripts from "site/lib/load-scripts" 5 | import renderTOC from "site/lib/render-toc" 6 | import renderSupportTable from "site/lib/render-support-table" 7 | import polyfillCustomEvent from "lib/custom-event" 8 | 9 | const DESKTOP_MIN_WIDTH = 1080 10 | 11 | const LIBRARY_SCRIPTS = [ 12 | "./embed-box.js", 13 | "./embed-box-custom.js", 14 | "./embed-box-custom-target.js" 15 | ] 16 | 17 | const CONSTRUCTOR_DEFAULTS = {} 18 | 19 | document.addEventListener("DOMContentLoaded", () => { 20 | // :active style fix for Safari 21 | document.addEventListener("touchstart", () => {}, true) 22 | polyfillCustomEvent({window, document}) 23 | 24 | const targetIDExample = document.querySelector("[data-example-id='target-ids'] .hljs-comment") 25 | const PRISTINE_GLOBALS = window.PRISTINE_GLOBALS = { 26 | EmbedBox: window.EmbedBox, 27 | EmbedBoxCustom: window.EmbedBoxCustom 28 | } 29 | const automatedFrame = document.getElementById("automated-frame") 30 | const automatedFrameDocument = automatedFrame.contentDocument 31 | const runInlineContainer = document.getElementById("run-inline-container") 32 | let demoInstance = null 33 | let createInteractiveDemo 34 | 35 | renderTOC() 36 | renderSupportTable(window.EmbedBox) 37 | 38 | targetIDExample.textContent = targetIDExample.textContent 39 | .replace("{{TARGET_IDS}}", `[${window.EmbedBox.getTargetIDs().join(", ")}]`) 40 | 41 | 42 | function bindObjectArguments(Constructor, boundSpec = {}) { 43 | return function BoundConstructor(spec) { 44 | demoInstance = new Constructor({...boundSpec, ...spec}) 45 | 46 | return demoInstance 47 | } 48 | } 49 | 50 | function onAutomatedFrameLoaded() { 51 | function runDemoSequence() { 52 | createInteractiveDemo = runDemo(automatedFrame, () => { 53 | createInteractiveDemo() 54 | }) 55 | } 56 | 57 | const style = automatedFrameDocument.createElement("style") 58 | 59 | style.innerHTML = ` 60 | html, body { 61 | margin: 0; 62 | padding: 0; 63 | } 64 | ` 65 | automatedFrameDocument.head.appendChild(style) 66 | 67 | loadScripts(LIBRARY_SCRIPTS, automatedFrameDocument, runDemoSequence) 68 | } 69 | 70 | if (automatedFrameDocument.readyState === "complete") { 71 | onAutomatedFrameLoaded() 72 | } 73 | else { 74 | automatedFrame.onLoad = onAutomatedFrameLoaded 75 | } 76 | 77 | function stopAutomatedDemo() { 78 | if (createInteractiveDemo) { 79 | // The hero automated demo takes focus from other inputs. 80 | // Switching to the interactive demo prevents this. 81 | createInteractiveDemo() 82 | createInteractiveDemo = null 83 | } 84 | } 85 | 86 | function evalRunButton(button) { 87 | const {parentElement} = button 88 | const useModal = button.getAttribute("data-run") === "modal" 89 | const example = parentElement.querySelector("code").textContent 90 | 91 | if (demoInstance) { 92 | demoInstance.destroy() 93 | demoInstance = null 94 | } 95 | stopAutomatedDemo() 96 | 97 | // Clear previous demo routing. 98 | if (window.history.pushState) { 99 | window.history.pushState("", "", window.location.pathname) 100 | } 101 | 102 | CONSTRUCTOR_DEFAULTS.container = useModal ? document.body : runInlineContainer 103 | 104 | Object.keys(PRISTINE_GLOBALS).forEach(key => { 105 | window[key] = bindObjectArguments(PRISTINE_GLOBALS[key], CONSTRUCTOR_DEFAULTS) 106 | }) 107 | window.eval(example) // eslint-disable-line no-eval 108 | } 109 | 110 | const buttons = Array.from(document.querySelectorAll("button[data-run]")) 111 | 112 | buttons.forEach(element => element.addEventListener("click", evalRunButton.bind(null, element))) 113 | 114 | if (document.body.clientWidth >= DESKTOP_MIN_WIDTH) { 115 | CONSTRUCTOR_DEFAULTS.events = { 116 | onLoad() { 117 | const instanceElement = this.application.element 118 | 119 | instanceElement.addEventListener("mouseover", stopAutomatedDemo) 120 | instanceElement.addEventListener("click", stopAutomatedDemo) 121 | 122 | delete CONSTRUCTOR_DEFAULTS.events 123 | } 124 | } 125 | evalRunButton(buttons[0]) 126 | } 127 | }) 128 | -------------------------------------------------------------------------------- /app/site/lib/is-element-partially-in-viewport.js: -------------------------------------------------------------------------------- 1 | export default function isElementPartiallyInViewport(element) { 2 | const {left, top, height, width} = element.getBoundingClientRect() 3 | const windowHeight = window.innerHeight || document.documentElement.clientHeight 4 | const windowWidth = window.innerWidth || document.documentElement.clientWidth 5 | 6 | const inViewVertically = top <= windowHeight && top + height >= 0 7 | const inViewHorizontally = left <= windowWidth && left + width >= 0 8 | 9 | return inViewVertically && inViewHorizontally 10 | } 11 | -------------------------------------------------------------------------------- /app/site/lib/load-scripts.js: -------------------------------------------------------------------------------- 1 | export default function loadScripts(scriptPaths, document, onComplete = () => {}) { 2 | let {length} = scriptPaths 3 | 4 | function onload() { 5 | length-- 6 | if (length === 0) onComplete() 7 | } 8 | 9 | scriptPaths.forEach(src => { 10 | const script = document.createElement("script") 11 | 12 | Object.assign(script, {src, onload}) 13 | document.head.appendChild(script) 14 | }) 15 | } 16 | -------------------------------------------------------------------------------- /app/site/lib/render-support-table.js: -------------------------------------------------------------------------------- 1 | const booleanToLabel = boolean => ({ 2 | label: boolean ? "✓" : "✗", 3 | supported: !!boolean 4 | }) 5 | 6 | function targetToRow({supports}) { 7 | const {embedCode, plugin, insertInto = {}} = supports 8 | 9 | return [ 10 | embedCode, 11 | plugin, 12 | insertInto.head, 13 | insertInto.body 14 | ].map(booleanToLabel) 15 | } 16 | 17 | function rowTemplate(html, {label, supported = ""}) { 18 | return `${html}${label}` 19 | } 20 | 21 | export default function renderSupportTable(EmbedBox) { 22 | const tableBody = document.querySelector("#target-supports tbody") 23 | 24 | EmbedBox.fetchedTargets.forEach(Target => { 25 | const row = document.createElement("tr") 26 | const cells = [{label: `${Target.id}`}].concat(targetToRow(Target)) 27 | 28 | row.innerHTML = cells.reduce(rowTemplate, "") 29 | 30 | tableBody.appendChild(row) 31 | }) 32 | } 33 | -------------------------------------------------------------------------------- /app/site/lib/render-toc.js: -------------------------------------------------------------------------------- 1 | import createSticky from "stickyfill" 2 | 3 | export default function renderTOC() { 4 | const sticky = createSticky() 5 | const toc = document.querySelector(".table-of-contents") 6 | const docsNav = document.querySelector(".docs-nav > .sticky") 7 | const demoWrapper = document.querySelector(".demo-wrapper > .sticky") 8 | 9 | Array 10 | .from(document.querySelectorAll("h2.headline-with-anchor [name], h3.headline-with-anchor [name]")) 11 | .forEach(({parentNode, href, textContent}) => { 12 | const ul = parentNode.tagName === "H3" ? toc.lastChild.lastChild : toc 13 | const li = document.createElement("li") 14 | const a = document.createElement("a") 15 | 16 | Object.assign(a, {href, textContent}) 17 | 18 | li.appendChild(a) 19 | ul.appendChild(li) 20 | 21 | if (parentNode.tagName === "H2") { 22 | const nextUl = document.createElement("ul") 23 | 24 | li.appendChild(nextUl) 25 | } 26 | }) 27 | 28 | sticky.add(docsNav) 29 | sticky.add(demoWrapper) 30 | } 31 | -------------------------------------------------------------------------------- /app/site/segment.js: -------------------------------------------------------------------------------- 1 | (function initSegment() { 2 | // Create a queue, but don't obliterate an existing one! 3 | const analytics = window.analytics = window.analytics || [] 4 | 5 | // If the real analytics.js is already on the page return. 6 | if (analytics.initialize) return 7 | 8 | // If the snippet was invoked already show an error. 9 | if (analytics.invoked) { 10 | if (window.console && console.error) { 11 | console.error("Segment snippet included twice.") 12 | } 13 | return 14 | } 15 | 16 | // Invoked flag, to make sure the snippet 17 | // is never invoked twice. 18 | analytics.invoked = true 19 | 20 | // A list of the methods in Analytics.js to stub. 21 | analytics.methods = [ 22 | "trackSubmit", 23 | "trackClick", 24 | "trackLink", 25 | "trackForm", 26 | "pageview", 27 | "identify", 28 | "reset", 29 | "group", 30 | "track", 31 | "ready", 32 | "alias", 33 | "page", 34 | "once", 35 | "off", 36 | "on" 37 | ] 38 | 39 | // Define a factory to create stubs. These are placeholders 40 | // for methods in Analytics.js so that you never have to wait 41 | // for it to load to actually record data. The `method` is 42 | // stored as the first argument, so we can replay the data. 43 | analytics.factory = function(method) { 44 | return function() { 45 | const args = Array.prototype.slice.call(arguments) 46 | 47 | args.unshift(method) 48 | analytics.push(args) 49 | return analytics 50 | } 51 | } 52 | 53 | // For each of our methods, generate a queueing stub. 54 | for (let i = 0; i < analytics.methods.length; i++) { 55 | const key = analytics.methods[i] 56 | 57 | analytics[key] = analytics.factory(key) 58 | } 59 | 60 | // Define a method to load Analytics.js from our CDN, 61 | // and that will be sure to only ever load it once. 62 | analytics.load = key => { 63 | // Create an async script element based on your key. 64 | const script = document.createElement("script") 65 | 66 | script.type = "text/javascript" 67 | script.async = true 68 | script.src = (document.location.protocol === "https:" ? "https://" : "http://") + 69 | `cdn.segment.com/analytics.js/v1/${key}/analytics.min.js` 70 | 71 | // Insert our script next to the first script element. 72 | const first = document.getElementsByTagName("script")[0] 73 | 74 | first.parentNode.insertBefore(script, first) 75 | } 76 | 77 | // Add a version to keep track of what"s in the wild. 78 | analytics.SNIPPET_VERSION = "3.1.0" 79 | 80 | // Load Analytics.js with your key, which will automatically 81 | // load the tools you"ve enabled for your account. Boosh! 82 | analytics.load("axfoaXqFtPG3M7fbktZPDXB2bHoph4dP") 83 | 84 | // Make the first page call to load the integrations. If 85 | // you"d like to manually name or tag the page, edit or 86 | // move this call however you"d like. 87 | analytics.page() 88 | }()) 89 | -------------------------------------------------------------------------------- /app/site/share-icons.pug: -------------------------------------------------------------------------------- 1 | .share-icons 2 | a.share-icon(href="http://www.facebook.com/sharer.php?u=http%3A%2F%2Fembedbox.io" target="_blank") 3 | svg(version="1.1" viewBox="0 0 16 16" fill="#3b5998") 4 | path(d="M4.025,5.291H5.68V4.541V3.805V3.683c0-0.708,0.018-1.802,0.533-2.479C6.755,0.487,7.5,0,8.781,0 c2.087,0,2.966,0.297,2.966,0.297l-0.414,2.451c0,0-0.689-0.199-1.333-0.199c-0.643,0-1.219,0.23-1.219,0.873v0.26v0.858v0.751 h2.638l-0.184,2.393H8.781V16H5.68V7.684H4.025V5.291") 5 | a.share-icon(href="https://twitter.com/intent/tweet/?text=An%20open-source%20UI%20which%20makes%20it%20easy%20for%20your%20users%20to%20install%20your%20embed%20code.&url=http%3A%2F%2Fembedbox.io&via=EmbedBox" target="_blank") 6 | svg(version="1.1" viewBox="0 0 16 16" fill="#00aced") 7 | path(d="M16,3.536c-0.589,0.261-1.221,0.438-1.885,0.517c0.678-0.406,1.198-1.05,1.443-1.816c-0.634,0.376-1.337,0.649-2.085,0.797 c-0.599-0.638-1.452-1.037-2.396-1.037c-1.813,0-3.283,1.47-3.283,3.282c0,0.257,0.029,0.508,0.085,0.748 c-2.728-0.137-5.147-1.444-6.766-3.43c-0.283,0.485-0.444,1.049-0.444,1.65c0,1.139,0.579,2.144,1.46,2.732 C1.592,6.963,1.086,6.816,0.643,6.57c0,0.014,0,0.027,0,0.041c0,1.59,1.132,2.917,2.633,3.219C3,9.905,2.71,9.945,2.411,9.945 c-0.212,0-0.417-0.021-0.618-0.059c0.418,1.304,1.63,2.253,3.066,2.28c-1.123,0.88-2.539,1.405-4.077,1.405 c-0.265,0-0.526-0.016-0.783-0.046C1.453,14.456,3.178,15,5.032,15c6.038,0,9.34-5.002,9.34-9.34c0-0.142-0.003-0.284-0.01-0.425 C15.003,4.773,15.56,4.195,16,3.536z") 8 | a.share-icon(href="mailto:?subject=An%20open-source%20UI%20which%20makes%20it%20easy%20for%20your%20users%20to%20install%20your%20embed%20code.&body=http%3A%2F%2Fembedbox.io" target="_blank") 9 | svg(version="1.1" viewBox="0 0 24 24" fill="#e92c63") 10 | path(d="M22,4H2C0.897,4,0,4.897,0,6v12c0,1.103,0.897,2,2,2h20c1.103,0,2-0.897,2-2V6C24,4.897,23.103,4,22,4z M7.248,14.434 l-3.5,2C3.67,16.479,3.584,16.5,3.5,16.5c-0.174,0-0.342-0.09-0.435-0.252c-0.137-0.239-0.054-0.545,0.186-0.682l3.5-2 c0.24-0.137,0.545-0.054,0.682,0.186C7.571,13.992,7.488,14.297,7.248,14.434z M12,14.5c-0.094,0-0.189-0.026-0.271-0.08l-8.5-5.5 C2.997,8.77,2.93,8.46,3.081,8.229c0.15-0.23,0.459-0.298,0.691-0.147L12,13.405l8.229-5.324c0.232-0.15,0.542-0.084,0.691,0.147 c0.15,0.232,0.083,0.542-0.148,0.691l-8.5,5.5C12.189,14.474,12.095,14.5,12,14.5z M20.934,16.248 C20.842,16.41,20.673,16.5,20.5,16.5c-0.084,0-0.169-0.021-0.248-0.065l-3.5-2c-0.24-0.137-0.323-0.442-0.186-0.682 s0.443-0.322,0.682-0.186l3.5,2C20.988,15.703,21.071,16.009,20.934,16.248z") 11 | -------------------------------------------------------------------------------- /app/styl/body-typography.styl: -------------------------------------------------------------------------------- 1 | @import fonts 2 | 3 | html 4 | font-size 16px 5 | 6 | body 7 | font-family sansSerifFonts 8 | -------------------------------------------------------------------------------- /app/styl/box-sizing-border-box-all.styl: -------------------------------------------------------------------------------- 1 | *, *:after, *:before 2 | box-sizing border-box 3 | -------------------------------------------------------------------------------- /app/styl/buttons.styl: -------------------------------------------------------------------------------- 1 | @import "styl/fonts" 2 | @import "styl/font-smoothing" 3 | @import "styl/media-query-variables" 4 | 5 | .button 6 | subpixelAntialiasedFonts() 7 | position relative 8 | text-rendering optimizeLegibility 9 | -webkit-tap-highlight-color transparent 10 | user-select none 11 | appearance none 12 | display inline-block 13 | cursor pointer 14 | border 0 15 | border-radius .1875em 16 | font-size 1em 17 | padding .6em 2em 18 | margin 0 19 | text-align center 20 | font-family sansSerifFonts 21 | font-weight 300 22 | letter-spacing .04em 23 | text-indent @letter-spacing 24 | text-decoration none 25 | 26 | @media chromeAndSafariOnlyQuery 27 | font-weight 400 28 | 29 | @media chromeOnlyQuery 30 | font-weight 300 31 | 32 | &:hover 33 | text-decoration none 34 | 35 | &[disabled] 36 | opacity .7 37 | 38 | &:hover, &:focus, &:focus:hover 39 | box-shadow none !important 40 | 41 | &:hover 42 | box-shadow 0 .1875em .375em -.1875em rgba(#000, .325) 43 | 44 | &:hover:active 45 | box-shadow inset 0 .125em .375em rgba(#000, .325) 46 | 47 | &:focus 48 | outline none 49 | 50 | &::before 51 | // `px` below to avoid `em` rounding issues 52 | content "" 53 | position absolute 54 | z-index 1 55 | top 2px 56 | right 2px 57 | bottom 2px 58 | left 2px 59 | border-radius .1em 60 | box-shadow inset 0 0 0 1px currentColor 61 | pointer-events none 62 | transition opacity .3s ease-in-out 63 | 64 | &:active::before 65 | opacity 0 66 | 67 | &.primary 68 | background #000 69 | color #fff 70 | -------------------------------------------------------------------------------- /app/styl/code-colors.styl: -------------------------------------------------------------------------------- 1 | codeGray = #75715e 2 | codeGold = #e6db74 3 | codeGreen = #a6e22e 4 | codeRed = #f92672 5 | codeBlue = #53d2d9 6 | codePurple = #9d60ff 7 | -------------------------------------------------------------------------------- /app/styl/code-syntax-highlighting.styl: -------------------------------------------------------------------------------- 1 | @import colors 2 | @import code-colors 3 | 4 | code[class*="lang-"] 5 | 6 | > span 7 | color inherit 8 | 9 | .hljs-string 10 | color codeGold 11 | 12 | .hljs-comment 13 | color codeGray 14 | 15 | .hljs-atom, .hljs-number 16 | color codeGreen 17 | 18 | &.lang-css 19 | 20 | .hljs-selector-tag, .hljs-meta 21 | color codeRed 22 | 23 | .hljs-attribute 24 | color codeBlue 25 | 26 | .hljs-builtin, .hljs-selector-class, .hljs-selector-pseudo, .hljs-selector-attr, .hljs-selector-id 27 | color codeGreen 28 | 29 | .hljs-built_in 30 | color codeBlue 31 | 32 | .hljs-property, .hljs-number 33 | color codePurple 34 | 35 | .hljs-tag 36 | color codeGreen 37 | 38 | .hljs-qualifier, .hljs-def, .hljs-keyword 39 | color codeRed 40 | 41 | &.lang-stylus 42 | 43 | .hljs-qualifier 44 | color codeGreen 45 | 46 | .hljs-tag 47 | color codeRed 48 | 49 | &.lang-html 50 | 51 | .hljs-tag .hljs-name 52 | color codeRed 53 | 54 | .hljs-attribute, .hljs-attr 55 | color codeGreen 56 | 57 | .hljs-string 58 | color codeGold 59 | 60 | .css 61 | 62 | .hljs-selector-tag 63 | color codeRed 64 | 65 | .hljs-attribute 66 | color codeBlue 67 | 68 | &.lang-javascript 69 | 70 | .hljs-literal 71 | color codePurple 72 | 73 | .hljs-subst 74 | color inherit 75 | 76 | .hljs-keyword 77 | color codeRed 78 | 79 | .hljs-def, .hljs-variable-2 80 | color codeGreen 81 | -------------------------------------------------------------------------------- /app/styl/colors.styl: -------------------------------------------------------------------------------- 1 | selectionColor = #b4d5fe 2 | 3 | darkGray = #2b2b2b 4 | gray = #e0e0e0 5 | lightGray = #ccc 6 | lightGrayRGBA = rgba(#000, .045) 7 | lightLineGrayRGBA = rgba(#000, .21) 8 | 9 | warnBackgroundColor = #fff5d6 10 | warnColor = #713b1b 11 | 12 | brandBlue = #2d88f3 13 | brandYellow = #e6db74 14 | 15 | errorRed = #c62838 16 | lightRed = hsl(0,100%,72%) 17 | 18 | lightGreen = hsl(100,100%,88%) 19 | -------------------------------------------------------------------------------- /app/styl/copyable-code.styl: -------------------------------------------------------------------------------- 1 | @import colors 2 | @import fonts 3 | @import media-query-variables 4 | 5 | .copyable-code-wrapper 6 | display block 7 | position relative 8 | height 2.375em 9 | 10 | .copy-button.button.primary 11 | position relative 12 | height 100% 13 | vertical-align middle 14 | z-index 1 15 | font-weight normal 16 | padding-top .55em 17 | padding-bottom .6em 18 | padding-left 1.25em 19 | padding-right 1.25em 20 | border-top-right-radius 0 21 | border-bottom-right-radius 0 22 | width 5.4125rem 23 | 24 | @media mobileMaxWidthQuery 25 | display none 26 | 27 | &.zeroclipboard-is-hover 28 | box-shadow 0 .1875em .375em -.1875em rgba(#000, .325) 29 | 30 | &.zeroclipboard-is-active 31 | box-shadow inset 0 .125em .375em rgba(#000, .325) 32 | 33 | @media mobileMaxWidthQuery 34 | display none 35 | 36 | @media firefoxOnlyQuery 37 | top -.0625em 38 | 39 | .standard.code.embed-code 40 | height 100% 41 | margin-left -1px 42 | border-top-left-radius 0 43 | border-bottom-left-radius 0 44 | font-size .8em 45 | padding .75em .8em 46 | width calc(100% - 5.4125rem) 47 | 48 | @media mobileMaxWidthQuery 49 | width 100% 50 | overflow ellipsis 51 | margin-left 0 52 | border-radius .1875rem 53 | 54 | .copied-message 55 | position absolute 56 | top 100% 57 | left 0 58 | z-index 3 59 | background rgba(#000, .9) 60 | color #fff 61 | font-family sansSerifFonts 62 | border-radius .25em 63 | padding .5em 1em 64 | margin-top .6em 65 | 66 | &::before 67 | content "" 68 | position absolute 69 | overflow hidden 70 | bottom 100% 71 | left 1em 72 | border-left .5em solid transparent 73 | border-right .5em solid transparent 74 | border-bottom .5em solid rgba(#000, .9) 75 | -------------------------------------------------------------------------------- /app/styl/font-smoothing.styl: -------------------------------------------------------------------------------- 1 | antialiasedFonts() 2 | -webkit-font-smoothing antialiased 3 | -moz-osx-font-smoothing grayscale 4 | 5 | subpixelAntialiasedFonts() 6 | -webkit-font-smoothing subpixel-antialiased 7 | -moz-osx-font-smoothing auto 8 | 9 | slightlyDarkerAntialiasedFonts() 10 | subpixelAntialiasedFonts() 11 | opacity .9999 12 | -------------------------------------------------------------------------------- /app/styl/fonts.styl: -------------------------------------------------------------------------------- 1 | sansSerifFonts = "Avenir New", Avenir, "Helvetica Neue", sans-serif 2 | monospaceFonts = Monaco, "Bitstream Vera Sans Mono", "Lucida Console", Terminal, monospace 3 | -------------------------------------------------------------------------------- /app/styl/inline-code.styl: -------------------------------------------------------------------------------- 1 | @import fonts 2 | 3 | code.inline 4 | font-family monospaceFonts 5 | font-size .727272em 6 | display inline-block 7 | vertical-align middle 8 | margin 0 .25em 9 | position relative 10 | top -1px 11 | -------------------------------------------------------------------------------- /app/styl/inline-svg.styl: -------------------------------------------------------------------------------- 1 | SVG = { 2 | play: "data:image/svg+xml;utf8," 3 | } 4 | -------------------------------------------------------------------------------- /app/styl/link-underlines.styl: -------------------------------------------------------------------------------- 1 | @import colors 2 | @import media-query-variables 3 | 4 | textShadowToCropUnderline(color) 5 | text-shadow .03em 0 color, -.03em 0 color, 0 .03em color, 0 -.03em color, .06em 0 color, -.06em 0 color, .09em 0 color, -.09em 0 color, .12em 0 color, -.12em 0 color, .15em 0 color, -.15em 0 color 6 | 7 | linkUnderlines(backgroundColor, color, lineTop = 87%) 8 | color color 9 | text-decoration none 10 | background-image linear-gradient(backgroundColor, backgroundColor), linear-gradient(backgroundColor, backgroundColor), linear-gradient(color, color) 11 | background-size .1em 1px, .1em 1px, 1px 1px 12 | background-repeat no-repeat, no-repeat, repeat-x 13 | textShadowToCropUnderline backgroundColor 14 | background-position 0% lineTop, 100% lineTop, 0% lineTop 15 | 16 | @media retinaQuery 17 | background-image linear-gradient(transparent 50%, backgroundColor, backgroundColor), linear-gradient(transparent 50%, backgroundColor, backgroundColor), linear-gradient(transparent 50%, color, color) 18 | background-size .075em 1px, .075em 1px, 1px 1px 19 | background-position 0% (lineTop - 2%), 100% (lineTop - 2%), 0% (lineTop - 2%) 20 | 21 | &::selection 22 | text-shadow none 23 | background selectionColor 24 | 25 | &::before, &::after, *, *::before, *::after 26 | text-shadow none 27 | 28 | &:visited 29 | color color 30 | -------------------------------------------------------------------------------- /app/styl/loading-dots.styl: -------------------------------------------------------------------------------- 1 | .loading-dots 2 | opacity 0 3 | animation loading-dots-fadein .5s linear forwards 4 | 5 | &[data-state="loaded"] 6 | i, i:first-child, i:last-child 7 | opacity 0 8 | animation-play-state paused 9 | 10 | i 11 | width .5em 12 | height .5em 13 | display inline-block 14 | vertical-align middle 15 | background currentColor 16 | border-radius 50% 17 | margin 0 .25em 18 | animation loading-dots-middle-dots .5s linear infinite 19 | 20 | &:first-child 21 | animation loading-dots-first-dot .5s linear infinite 22 | opacity 0 23 | transform translate(-1em) 24 | 25 | &:last-child 26 | animation loading-dots-last-dot .5s linear infinite 27 | 28 | @keyframes loading-dots-fadein 29 | 100% 30 | opacity 1 31 | 32 | @keyframes loading-dots-first-dot 33 | 100% 34 | transform translate(1em) 35 | opacity 1 36 | 37 | @keyframes loading-dots-middle-dots 38 | 100% 39 | transform translate(1em) 40 | 41 | @keyframes loading-dots-last-dot 42 | 100% 43 | transform translate(2em) 44 | opacity 0 45 | -------------------------------------------------------------------------------- /app/styl/markdown.styl: -------------------------------------------------------------------------------- 1 | @import colors 2 | 3 | .markdown 4 | 5 | > *:first-child 6 | margin-top 0 7 | 8 | > *:last-child 9 | margin-bottom 0 10 | 11 | img 12 | margin 1em 0 13 | display block 14 | max-width 100% 15 | 16 | sup 17 | vertical-align baseline 18 | position relative 19 | top -.5em 20 | font-size .85em 21 | 22 | h1, h2, h3, h4, h5, h6 23 | font-weight 600 24 | line-height 1.2em 25 | margin-top 2rem 26 | margin-bottom .125em 27 | 28 | & + * 29 | margin-top 0 30 | 31 | h1 + h2, h2 + h3, h3 + h4, h4 + h5, h5 + h6 32 | margin-top 1em 33 | 34 | code, pre 35 | font-family monospaceFonts 36 | 37 | pre 38 | background-color lightGrayRGBA 39 | color #333 40 | padding .5em .666666em 41 | overflow-x auto 42 | overflow-scrolling touch 43 | font-size .8em 44 | line-height 1.71em 45 | white-space pre 46 | word-wrap normal 47 | 48 | code 49 | font-size .8em 50 | padding .15625em .3125em 51 | background lightGrayRGBA 52 | white-space nowrap 53 | font-style normal 54 | 55 | pre > code 56 | font-size inherit 57 | background transparent 58 | padding 0 59 | white-space inherit 60 | 61 | ol, ul, dl 62 | 63 | > li:not(.markdown-unstyled) 64 | margin-bottom .666em 65 | 66 | &:last-child 67 | margin-bottom 0 68 | 69 | > *:last-child 70 | margin-bottom 0 71 | 72 | dl 73 | margin 1.5em auto 74 | 75 | dt 76 | display inline-block 77 | line-height 2em 78 | border-left .25em solid 79 | 80 | hr 81 | border 0 82 | height 1px 83 | margin 1em 0 84 | background lightLineGrayRGBA 85 | 86 | &.with-no-margin 87 | margin-top 0 88 | margin-bottom 0 89 | -------------------------------------------------------------------------------- /app/styl/media-query-variables.styl: -------------------------------------------------------------------------------- 1 | @import sizes 2 | 3 | desktopMinWidth = 769px 4 | desktopMinWidthQuery = "(min-width: " + desktopMinWidth + ")" 5 | 6 | largeDesktopWidth = 1400px 7 | largeDesktopMinWidthQuery = "(min-width: " + largeDesktopWidth + ")" 8 | 9 | mobileMaxWidth = 768px 10 | mobileMaxWidthQuery = "(max-width: " + mobileMaxWidth + ")" 11 | 12 | largerThanIphoneMinWidth = 569px 13 | largerThanIphoneMinWidthQuery = "(min-width: " + largerThanIphoneMinWidth + ")" 14 | 15 | iPhoneMaxWidth = 568px 16 | iPhoneMaxWidthQuery = "(max-width: " + iPhoneMaxWidth + ")" 17 | iPhoneUICompensation = 64px 18 | 19 | firefoxOnlyQuery = "screen and (min--moz-device-pixel-ratio: 0)" 20 | 21 | chromeAndSafariOnlyQuery = "screen and (-webkit-min-device-pixel-ratio: 0)" 22 | 23 | chromeOnlyQuery = "all and (-webkit-min-device-pixel-ratio: 0) and (min-resolution: .001dppx)" 24 | 25 | retinaQuery = "only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx)" 26 | 27 | smallerThanTargetInstructionsMaxWidthQuery = "(max-width: " + (targetInstructionsMaxWidth + .125rem) + ")" 28 | -------------------------------------------------------------------------------- /app/styl/more-links-and-buttons.styl: -------------------------------------------------------------------------------- 1 | @css { 2 | @font-face { 3 | font-family: "embed-box-icons"; 4 | font-style: normal; 5 | font-weight: normal; 6 | src: url(data:application/x-font-woff;charset=utf-8;base64,d09GRk9UVE8AAAQQAAoAAAAABewAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABDRkYgAAAA9AAAARQAAAEw7LPuDUZGVE0AAAIIAAAAGgAAABx04jsnT1MvMgAAAiQAAABLAAAAYGFpBYRjbWFwAAACcAAAAEcAAAFOP7UHcGhlYWQAAAK4AAAALwAAADYGoUQqaGhlYQAAAugAAAAfAAAAJAe/AetobXR4AAADCAAAABAAAAAQCwoAAG1heHAAAAMYAAAABgAAAAYABFAAbmFtZQAAAyAAAADaAAABsE3GDFBwb3N0AAAD/AAAABMAAAAg/50AZnicTY69S8NQFMXvbV5aLI/4GXEIzSJYAh0dXPwXLNpgVymvH6AtpMHJsWglk06CuPXvEPyg9E9wt2SVt/huk2exWUo5HPgdONx7EBgDROTioiWCSqfR6/YBc4BwTKUcuQbtsTo3JGelIrBh2Y2iJfBCFM5GydB04GXdAdhwYLTpwJqDB1tgZjfysA0ueHAYdq5EP+i02mGl0RbXQa97KZpLXvm9OgMA73CI98AQ90+aN+onkgmXKCVpacjd2ST5+pvk5TywE056zgsW+XRrq281rX2m0zROYxXXTtU0zRS/n6lFVhl9mBY90sDW5/RUrZOnhV547JvWLw0Y+fp5/KbLJMgjUX1dlB92Zkd2xIv/gw+CN3icY2BgYGQAggsF9tdA9CWLvytgNABOBQe1AAB4nGNgZopgnMDAysDBasw6k4GBUQ5CM19nSGMSYgACVgYIaGBgYGJAAgFprikMDgzXFazY0v6lMexg/sIgDhRmhCtQAEJGABgTC0oAeJxjYGBgZoBgGQZGBhDwAPIYwXwWBh0gzQakGRmYGK4rWP3/D+RfV7D8//+/FpAFUsUC1s0E5LAxQA0YnoCZibAaAF3eCGYAeJxjYGRgYADisx3H/eL5bb4ycHMwgMAli78rEPT/l8wCzF+AXA4GJpAoAFzJDHkAeJxjYGRgYP7y/yXDDmYBBoZ/b4EkUAQFsAAAloYFrwAEAAAAAf0AAAH9AAADEAAAAABQAAAEAAB4nI2PvQ3CMBCFXyCJxI8oEaULJCpHTiRSMEBKSvoIWVGaWHKYgREYgzEYgDEYgJoXc0UKCizZ/u7euzsbwBI3RBhWhAU2whMkMMJT7HAVjul5CCfkl3CKRbSiM4pnzKxD1cATzLEVnuKIUjim5y6ckJ/CKfkNixoNTw+NFmc4dOgBWzfW6/bsOgajvGSqEF/C7UO9QoGM/1A4cP/u+tVK5nI6NSsMac92rrtUzjdWFZlRBzWazqjUudGFyWn857WnoPfUB1VxwvAunKzvW9epPDN/9fkAFF9DNgAAeJxjYGYAg/+zGNIYsAAALpkCAwA=) format("woff"); 7 | } 8 | } 9 | 10 | chevronIconForMoreLinksAndButtons() 11 | font-family "embed-box-icons" 12 | position relative 13 | display inline-block 14 | vertical-align baseline 15 | color inherit 16 | font-style normal 17 | font-weight inherit 18 | font-size 1em 19 | line-height 1 20 | text-decoration none 21 | 22 | a.more, button.more, .with-more-icon-after 23 | 24 | &::after 25 | chevronIconForMoreLinksAndButtons() 26 | content "\203A" // › 27 | padding-left .3em 28 | 29 | a.before, .with-before-icon-before 30 | 31 | &::before 32 | chevronIconForMoreLinksAndButtons() 33 | content "\2039" // ‹ 34 | padding-right .3em 35 | 36 | a.more:not(.button)::after 37 | padding-right .3em 38 | 39 | .with-more-icon-after:empty::after 40 | padding-left .15em 41 | padding-right .15em 42 | -------------------------------------------------------------------------------- /app/styl/reset.styl: -------------------------------------------------------------------------------- 1 | article, aside, details, figcaption, figure, footer, header, hgroup, nav, section, summary 2 | display block 3 | 4 | audio, canvas, video 5 | display inline 6 | zoom 1 7 | 8 | audio:not([controls]) 9 | display none 10 | height 0 11 | 12 | [hidden] 13 | display none 14 | 15 | html 16 | font-size 100% 17 | text-size-adjust 100% 18 | 19 | body 20 | margin 0 21 | text-rendering optimizeLegibility 22 | 23 | button, input, select, textarea 24 | font-family inherit 25 | font-size inherit 26 | margin 0 27 | 28 | button, input 29 | line-height normal 30 | 31 | button, input[type="button"], input[type="reset"], input[type="submit"] 32 | cursor pointer 33 | 34 | &[disabled] 35 | cursor not-allowed 36 | 37 | button::-moz-focus-inner, input::-moz-focus-inner 38 | border 0 39 | padding 0 40 | 41 | a 42 | 43 | &:focus 44 | outline thin dotted 45 | 46 | &:active, &:hover 47 | outline 0 48 | 49 | abbr[title] 50 | border-bottom thin dotted 51 | 52 | b, strong 53 | font-weight 700 54 | 55 | dfn 56 | font-style italic 57 | 58 | pre 59 | white-space pre-wrap 60 | word-wrap break-word 61 | 62 | img 63 | border 0 64 | -ms-interpolation-mode bicubic 65 | 66 | svg:not(:root) 67 | overflow hidden 68 | 69 | textarea 70 | overflow auto 71 | -webkit-overflow-scrolling touch 72 | vertical-align top 73 | resize vertical 74 | 75 | table 76 | border-collapse collapse 77 | border-spacing 0 78 | 79 | figure, form 80 | margin 0 81 | 82 | p, pre, dl, menu, ol, ul 83 | margin 1em 0 84 | -------------------------------------------------------------------------------- /app/styl/sizes.styl: -------------------------------------------------------------------------------- 1 | centeredPageWidth = 48em 2 | standardInputRadius = .1875em 3 | 4 | targetInstructionsMaxWidth = 35rem 5 | -------------------------------------------------------------------------------- /app/targets/drupal/activate-plugin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/embed-box/14e8488bf334bb34038a4129d39d6ecd32078179/app/targets/drupal/activate-plugin.png -------------------------------------------------------------------------------- /app/targets/drupal/drupal-7/activate-module/activate-module.pug: -------------------------------------------------------------------------------- 1 | .screenshot 2 | .menu 3 | .item Dashboard 4 | .item Content 5 | .item Structure 6 | .item Appearance 7 | .item People 8 | .item.selected.focal-point.relative-arrow(data-arrow="left") Modules 9 | .item Configuration 10 | 11 | .menu.sub 12 | .item Add content 13 | .item Find content 14 | 15 | .modules-list(data-flow="column") 16 | .title User Interface 17 | table.entries 18 | thead 19 | th ENABLED 20 | th NAME 21 | th DESCRIPTION 22 | tbody 23 | tr 24 | td 25 | div.relative-arrow(data-arrow="right") 26 | input(type="checkbox" checked) 27 | td!= config.name 28 | td 29 | 30 | footer(data-arrow="right") 31 | button.focal-point Save configuration 32 | -------------------------------------------------------------------------------- /app/targets/drupal/drupal-7/activate-module/activate-module.styl: -------------------------------------------------------------------------------- 1 | body 2 | width 700px 3 | height 300px 4 | 5 | button 6 | background-color #ededed 7 | border none 8 | border-radius 1em 9 | line-height 2 10 | padding 0 .8em 11 | 12 | .menu 13 | align-items center 14 | flex-flow row wrap 15 | background black 16 | color white 17 | padding .5em 18 | 19 | &.sub 20 | background-color #666 21 | 22 | .item 23 | line-height 1.5 24 | padding 0 .8em 25 | 26 | &.selected 27 | background-color #999 28 | border-radius .8em 29 | text-shadow 0 1px 0 #000 30 | 31 | .modules-list 32 | border 1px #ccc solid 33 | margin 1em 1em 34 | padding 1em 35 | 36 | .entries 37 | border 1px #ccc solid 38 | width 100% 39 | 40 | th 41 | background-color #eee 42 | border 1px solid #ccc 43 | padding .2em 1em 44 | th:last-of-type 45 | width 100% 46 | 47 | td 48 | text-align center 49 | 50 | footer 51 | padding 1em 52 | -------------------------------------------------------------------------------- /app/targets/drupal/drupal-7/activate-module/index.js: -------------------------------------------------------------------------------- 1 | import template from "./activate-module.pug" 2 | import stylesheet from "./activate-module.styl" 3 | 4 | import BaseScreenshot from "components/base-screenshot" 5 | 6 | export default class Screenshot extends BaseScreenshot { 7 | static template = template; 8 | static stylesheet = stylesheet; 9 | } 10 | -------------------------------------------------------------------------------- /app/targets/drupal/drupal-7/drupal-7.pug: -------------------------------------------------------------------------------- 1 | ol.steps 2 | if this.pluginURL 3 | li 4 | != this.renderDownloadLink() 5 | p After downloading, don’t unzip the file. 6 | 7 | li 8 | h2 Login to your Drupal Administrator Dashboard and click Modules. 9 | 10 | figure(data-ref="screenshotMounts[]" data-screenshot="navigateToModules") 11 | 12 | li 13 | h2 Click Install New Module. 14 | 15 | figure(data-ref="screenshotMounts[]" data-screenshot="installNewModules") 16 | 17 | li 18 | h2 Upload the module. 19 | p Click Choose File and select the module you downloaded to your computer. 20 | 21 | figure(data-ref="screenshotMounts[]" data-screenshot="uploadModule") 22 | 23 | li 24 | h2 Click Enable newly added modules. 25 | 26 | figure(data-ref="screenshotMounts[]" data-screenshot="installationSuccessful") 27 | 28 | li 29 | h2 Activate the plugin and view your site. 30 | 31 | p On the Modules page, scroll down to find the new #{config.name} entry. 32 | p Check the Enabled. checkbox to activate the plugin, and click Save configuration. 33 | 34 | figure(data-ref="screenshotMounts[]" data-screenshot="activateModule") 35 | 36 | p You’re done! 37 | 38 | else 39 | if this.location === "body" 40 | li 41 | h2 In your Drupal site’s Admin interface, click the Structure link at the top of the page. 42 | 43 | li 44 | h2 Click Blocks. 45 | 46 | li 47 | h2 Click Add Block. 48 | 49 | li 50 | h2 Fill out the form. 51 | 52 | p As the Block Description enter “#{ config.name } Embed”. 53 | p As the Block Body paste this embed code: 54 | 55 | .copy-container(data-ref="copyContainers[]") 56 | button.button.primary.run(data-ref="copyButtons[]") Copy 57 | div.copyable(contenteditable)= this.copyText 58 | 59 | p As the Text Format select “Full HTML”. 60 | 61 | p Under Region Settings select “Footer” for every theme. 62 | 63 | p That’s it, there’s no need to select any other options 64 | 65 | li 66 | h2 Click Save block, you’re done! 67 | else 68 | li 69 | h2 If you don’t already have it installed, install the Add to Head module. 70 | 71 | p In your Drupal site’s Admin interface, click the Modules link at the top of the page 72 | p Click Install new module. 73 | p In the Install from a URL field enter: 74 | 75 | .copy-container(data-ref="copyContainers[]") 76 | button.button.primary.run(data-ref="copyButtons[]") Copy 77 | div.copyable(contenteditable) https://ftp.drupal.org/files/projects/add_to_head-7.x-1.2.tar.gz 78 | 79 | p Click Enable newly install modules. 80 | p Scroll down until you find the Add To Head module and check the box to the left of the name. 81 | p Click Save configuration. 82 | 83 | li 84 | h2 Install the embed code into the module 85 | 86 | p Click the Configuration button at the top of your Drupal site’s Admin interface. 87 | p Click the Add to Head link on the right side. 88 | p Click Add one now. 89 | 90 | li 91 | h2 Fill out the form. 92 | 93 | p For the Name enter “#{ config.name } Embed”. 94 | p For the Code enter: 95 | 96 | .copy-container(data-ref="copyContainers[]") 97 | button.button.primary.run(data-ref="copyButtons[]") Copy 98 | div.copyable(contenteditable)= this.copyText 99 | 100 | p For the Scope of addition, select “Head”. 101 | p There is no need to change any other fields. 102 | 103 | li 104 | h2 Click Save, you’re done! 105 | -------------------------------------------------------------------------------- /app/targets/drupal/drupal-7/index.js: -------------------------------------------------------------------------------- 1 | import template from "./drupal-7.pug" 2 | import activateModule from "./activate-module" 3 | import navigateToModules from "./navigate-to-modules" 4 | import installNewModules from "./install-new-modules" 5 | import uploadModule from "./upload-module" 6 | import installationSuccessful from "./installation-successful" 7 | 8 | export default { 9 | id: "7", 10 | template, 11 | screenshots: { 12 | activateModule, 13 | installationSuccessful, 14 | navigateToModules, 15 | installNewModules, 16 | uploadModule 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /app/targets/drupal/drupal-7/install-new-modules/index.js: -------------------------------------------------------------------------------- 1 | import template from "./install-new-modules.pug" 2 | import stylesheet from "./install-new-modules.styl" 3 | 4 | import BaseScreenshot from "components/base-screenshot" 5 | 6 | export default class Screenshot extends BaseScreenshot { 7 | static template = template; 8 | static stylesheet = stylesheet; 9 | } 10 | -------------------------------------------------------------------------------- /app/targets/drupal/drupal-7/install-new-modules/install-new-modules.pug: -------------------------------------------------------------------------------- 1 | .screenshot 2 | h2 Modules 3 | 4 | .modal(data-flow="column") 5 | .nav 6 | .item 7 | a(href="#-") Home 8 | .item 9 | a(href="#-") Administration 10 | 11 | .instructions(data-flow="column") 12 | p(data-arrow="right") 13 | a.install.focal-point(href="#-") Install new module 14 | 15 | .modules(data-flow="column") 16 | header Core 17 | 18 | table 19 | thead 20 | th Enabled 21 | th Name 22 | th Version 23 | th Description 24 | th Operations 25 | tbody 26 | -------------------------------------------------------------------------------- /app/targets/drupal/drupal-7/install-new-modules/install-new-modules.styl: -------------------------------------------------------------------------------- 1 | body 2 | width 600px 3 | height 300px 4 | background #333 5 | font-family serif 6 | color white 7 | padding 0 1em 8 | 9 | a 10 | text-decoration none 11 | 12 | &.install::before 13 | content "+" 14 | display inline-block 15 | font-weight bold 16 | margin 0 .4em 17 | 18 | p 19 | margin .5em 0 20 | 21 | h2 22 | color #ebe3c5 23 | font-weight normal 24 | margin .4em 0 25 | 26 | .modal 27 | background white 28 | color black 29 | padding 1.5em 2em 30 | 31 | .nav 32 | align-items center 33 | margin-bottom 1em 34 | 35 | .item 36 | & + .item::before 37 | content "»" 38 | display inline-block 39 | margin 0 .4em 40 | 41 | .modules 42 | border 1px solid #dadada 43 | border-radius 5px 44 | color #6d6a67 45 | font-family sans-serif 46 | padding-bottom 4em 47 | margin-top .5em 48 | 49 | header 50 | background #dbdbdb 51 | padding .3em .8em 52 | 53 | table 54 | width 100% 55 | thead 56 | background-color #747474 57 | color #fff 58 | 59 | th 60 | border 1px solid #fff 61 | -------------------------------------------------------------------------------- /app/targets/drupal/drupal-7/installation-successful/index.js: -------------------------------------------------------------------------------- 1 | import template from "./installation-successful.pug" 2 | import stylesheet from "./installation-successful.styl" 3 | 4 | import BaseScreenshot from "components/base-screenshot" 5 | 6 | export default class Screenshot extends BaseScreenshot { 7 | static template = template; 8 | static stylesheet = stylesheet; 9 | } 10 | -------------------------------------------------------------------------------- /app/targets/drupal/drupal-7/installation-successful/installation-successful.pug: -------------------------------------------------------------------------------- 1 | .screenshot 2 | header 3 | h2 Update Manager 4 | 5 | .content(data-flow="column") 6 | .alert Installation was completed successfully. 7 | 8 | h4!= config.name 9 | ul 10 | li Installed “#{config.name}” successfully 11 | 12 | h4 Next steps 13 | ul 14 | li 15 | a(href="#-" data-arrow="right") Enable newly added 16 | li 17 | a(href="#-") Adminstrator pages 18 | -------------------------------------------------------------------------------- /app/targets/drupal/drupal-7/installation-successful/installation-successful.styl: -------------------------------------------------------------------------------- 1 | body 2 | width 470px 3 | height 300px 4 | font-family sans-serif 5 | padding 0 2em 6 | 7 | header 8 | background-color #e0e0d8 9 | padding .3em .8em 10 | 11 | a 12 | text-decoration none 13 | 14 | p 15 | margin .5em 0 16 | 17 | h2 18 | font-weight normal 19 | margin .4em 0 20 | 21 | h3 22 | margin 1em 0 0 0 23 | 24 | .alert 25 | background-color #f8fef0 26 | border 1px solid #d2e0b6 27 | margin-top 1em 28 | padding .3em .8em 29 | 30 | ul 31 | margin 0 32 | padding 0 1em 33 | -------------------------------------------------------------------------------- /app/targets/drupal/drupal-7/navigate-to-modules/index.js: -------------------------------------------------------------------------------- 1 | import template from "./navigate-to-modules.pug" 2 | import stylesheet from "./navigate-to-modules.styl" 3 | 4 | import BaseScreenshot from "components/base-screenshot" 5 | 6 | export default class Screenshot extends BaseScreenshot { 7 | static template = template; 8 | static stylesheet = stylesheet; 9 | } 10 | -------------------------------------------------------------------------------- /app/targets/drupal/drupal-7/navigate-to-modules/navigate-to-modules.pug: -------------------------------------------------------------------------------- 1 | .screenshot 2 | .menu 3 | .item Dashboard 4 | .item Content 5 | .item Structure 6 | .item Appearance 7 | .item People 8 | .item.focal-point.relative-arrow(data-arrow="left") Modules 9 | .item Configuration 10 | 11 | .menu.sub 12 | .item Add content 13 | .item Find content 14 | 15 | .content 16 | h1 Administration 17 | -------------------------------------------------------------------------------- /app/targets/drupal/drupal-7/navigate-to-modules/navigate-to-modules.styl: -------------------------------------------------------------------------------- 1 | body 2 | width 700px 3 | height 160px 4 | 5 | .menu 6 | align-items center 7 | flex-flow row wrap 8 | background black 9 | color white 10 | padding .5em 11 | 12 | &.sub 13 | background-color #666 14 | 15 | .item 16 | line-height 1.5 17 | padding 0 .8em 18 | border-radius .8em 19 | 20 | .content 21 | background-color #e0e0d8 22 | padding 0 1em 23 | -------------------------------------------------------------------------------- /app/targets/drupal/drupal-7/upload-module/index.js: -------------------------------------------------------------------------------- 1 | import template from "./upload-modules.pug" 2 | import stylesheet from "./upload-modules.styl" 3 | 4 | import BaseScreenshot from "components/base-screenshot" 5 | 6 | export default class Screenshot extends BaseScreenshot { 7 | static template = template; 8 | static stylesheet = stylesheet; 9 | } 10 | -------------------------------------------------------------------------------- /app/targets/drupal/drupal-7/upload-module/upload-modules.pug: -------------------------------------------------------------------------------- 1 | .screenshot 2 | h2 Modules 3 | 4 | .modal(data-flow="column") 5 | .nav 6 | .item 7 | a(href="#-") Home 8 | .item 9 | a(href="#-") Administration 10 | .item 11 | a(href="#-") Modules 12 | 13 | .instructions(data-flow="column") 14 | p 15 | | The following extensions are supported:  16 | i zip tar tgz bz2 17 | 18 | p 19 | strong Upload a module or theme archive to install 20 | 21 | p 22 | .upload(data-arrow="right") 23 | input.focal-point(type="file") 24 | 25 | .hint For example:  26 | i name.tar.zip 27 | |  from your local computer 28 | 29 | footer(data-arrow="right") 30 | button.focal-point Install 31 | -------------------------------------------------------------------------------- /app/targets/drupal/drupal-7/upload-module/upload-modules.styl: -------------------------------------------------------------------------------- 1 | body 2 | width 500px 3 | height 300px 4 | background #333 5 | font-family serif 6 | color white 7 | padding 0 1em 8 | 9 | a 10 | text-decoration none 11 | 12 | p 13 | margin .5em 0 14 | 15 | button 16 | background-color #ededed 17 | border none 18 | border-radius 1em 19 | font-family sans-serif 20 | line-height 2 21 | padding 0 .8em 22 | 23 | h2 24 | color #ebe3c5 25 | font-weight normal 26 | margin .4em 0 27 | 28 | input[type="file"] 29 | width 14em 30 | 31 | .modal 32 | background white 33 | color black 34 | padding 1.5em 2em 35 | 36 | .nav 37 | align-items center 38 | margin-bottom 1em 39 | 40 | .item 41 | & + .item::before 42 | margin 0 .4em 43 | display inline-block 44 | content "»" 45 | 46 | -------------------------------------------------------------------------------- /app/targets/drupal/drupal-8/activate-module/activate-module.pug: -------------------------------------------------------------------------------- 1 | .screenshot 2 | h2 Extend 3 | 4 | .modal(data-flow="column") 5 | .nav 6 | .item 7 | a(href="#-") Home 8 | .item 9 | a(href="#-") Administration 10 | 11 | .instructions(data-flow="column") 12 | p Download additional contributed modules to extend Drupal's functionality. 13 | p 14 | | Regularly review and install available updates to maintain a secure and current site. 15 | | Always run the update script each time a module is updated. 16 | 17 | p 18 | button.install.with-plus-icon Install new module 19 | 20 | .modules(data-flow="column") 21 | header 22 | a(href="#-") Core 23 | 24 | table 25 | thead 26 | th 27 | th Name 28 | th Description 29 | tbody 30 | tr 31 | td.enable-toggle 32 | div.relative-arrow(data-arrow="right") 33 | input(type="checkbox" checked) 34 | td!= config.name 35 | td 36 | 37 | footer(data-arrow="right") 38 | button.focal-point Save configuration 39 | 40 | -------------------------------------------------------------------------------- /app/targets/drupal/drupal-8/activate-module/activate-module.styl: -------------------------------------------------------------------------------- 1 | body 2 | width 600px 3 | height 420px 4 | background #333 5 | color white 6 | padding 0 1em 7 | 8 | a 9 | text-decoration none 10 | 11 | button 12 | 13 | &.install 14 | background-color #4da5f0 15 | border 1px solid #2b69d2 16 | border-radius .7em 17 | color #fff 18 | padding .5em 1em .5em .7em 19 | 20 | &::before 21 | content "+" 22 | display inline-block 23 | font-weight bold 24 | margin-right .5em 25 | 26 | p 27 | margin .5em 0 28 | 29 | h2 30 | align-items center 31 | color #fff 32 | display flex 33 | font-weight normal 34 | margin .4em 0 35 | 36 | &::after 37 | border 1px solid #fff 38 | border-radius 50% 39 | content "+" 40 | display inline-block 41 | font-size 14px 42 | font-weight bold 43 | height 1em 44 | line-height .8 45 | margin 0 .4em 46 | text-align center 47 | width 1em 48 | 49 | .with-plus-icon::before 50 | content "+" 51 | display inline-block 52 | font-weight bold 53 | margin 0 .4em 54 | 55 | .modal 56 | background white 57 | color black 58 | padding 1.5em 2em 59 | 60 | .nav 61 | align-items center 62 | margin-bottom 1em 63 | 64 | .item 65 | & + .item::before 66 | content "»" 67 | display inline-block 68 | margin 0 .4em 69 | 70 | .modules 71 | border 1px solid #dadada 72 | font-family sans-serif 73 | padding-bottom 2em 74 | margin .5em 0 75 | 76 | header 77 | font-size 1.2em 78 | font-weight bold 79 | padding .3em .8em 80 | 81 | table 82 | width 100% 83 | 84 | thead, tr 85 | background-color #eee 86 | 87 | th, td 88 | border 1px solid #fff 89 | padding .5em 1em 90 | text-align left 91 | 92 | .enable-toggle 93 | text-align center 94 | -------------------------------------------------------------------------------- /app/targets/drupal/drupal-8/activate-module/index.js: -------------------------------------------------------------------------------- 1 | import template from "./activate-module.pug" 2 | import stylesheet from "./activate-module.styl" 3 | 4 | import BaseScreenshot from "components/base-screenshot" 5 | 6 | export default class Screenshot extends BaseScreenshot { 7 | static template = template; 8 | static stylesheet = stylesheet; 9 | } 10 | -------------------------------------------------------------------------------- /app/targets/drupal/drupal-8/drupal-8.pug: -------------------------------------------------------------------------------- 1 | ol.steps 2 | if this.pluginURL 3 | li 4 | != this.renderDownloadLink() 5 | p After downloading, don’t unzip the file. 6 | 7 | li 8 | h2 Login to your Drupal Administrator Dashboard and click Extend. 9 | 10 | figure(data-ref="screenshotMounts[]" data-screenshot="navigateToModules") 11 | 12 | li 13 | h2 Click Install new module. 14 | 15 | figure(data-ref="screenshotMounts[]" data-screenshot="installNewModules") 16 | 17 | li 18 | h2 Upload the module. 19 | p Click Choose File and select the module you downloaded to your computer. 20 | 21 | figure(data-ref="screenshotMounts[]" data-screenshot="uploadModule") 22 | 23 | li 24 | h2 Activate the module. 25 | 26 | p You should see the new module on the Extend page. 27 | p The module will appear in category set by the author. 28 | p Click the checkbox next to the module, then click Save Configuration. 29 | 30 | figure(data-ref="screenshotMounts[]" data-screenshot="activateModule") 31 | 32 | p You’re done! 33 | 34 | else 35 | li 36 | h2 In your Drupal site’s Admin interface, click the Structure Block layout Add custom block link in the navigation menu at the top of the page. 37 | 38 | li 39 | h2 Fill out the form. 40 | 41 | p As the Block Description enter “#{ config.name } Embed”. 42 | 43 | p Before pasting the embed code as the Text Format select “Full HTML”. 44 | 45 | p In the Body field click the Source button inside the editor. 46 | p Paste this embed code: 47 | 48 | .copy-container(data-ref="copyContainers[]") 49 | button.button.primary.run(data-ref="copyButtons[]") Copy 50 | div.copyable(contenteditable)= this.copyText 51 | 52 | p Click Save. 53 | 54 | p On the new page that opens, For the Region select “Footer first”. 55 | 56 | li 57 | h2 Click Save block, you’re done! 58 | -------------------------------------------------------------------------------- /app/targets/drupal/drupal-8/index.js: -------------------------------------------------------------------------------- 1 | import template from "./drupal-8.pug" 2 | import navigateToModules from "./navigate-to-modules" 3 | import installNewModules from "./install-new-modules" 4 | import uploadModule from "./upload-module" 5 | import activateModule from "./activate-module" 6 | 7 | export default { 8 | id: "8", 9 | template, 10 | screenshots: { 11 | activateModule, 12 | navigateToModules, 13 | installNewModules, 14 | uploadModule 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /app/targets/drupal/drupal-8/install-new-modules/index.js: -------------------------------------------------------------------------------- 1 | import template from "./install-new-modules.pug" 2 | import stylesheet from "./install-new-modules.styl" 3 | 4 | import BaseScreenshot from "components/base-screenshot" 5 | 6 | export default class Screenshot extends BaseScreenshot { 7 | static template = template; 8 | static stylesheet = stylesheet; 9 | } 10 | -------------------------------------------------------------------------------- /app/targets/drupal/drupal-8/install-new-modules/install-new-modules.pug: -------------------------------------------------------------------------------- 1 | .screenshot 2 | h2 Extend 3 | 4 | .modal(data-flow="column") 5 | .nav 6 | .item 7 | a(href="#-") Home 8 | .item 9 | a(href="#-") Administration 10 | 11 | .instructions(data-flow="column") 12 | p Download additional contributed modules to extend Drupal's functionality. 13 | p 14 | | Regularly review and install available updates to maintain a secure and current site. 15 | | Always run the update script each time a module is updated. 16 | 17 | p(data-arrow="right") 18 | button.install.with-plus-icon Install new module 19 | 20 | .modules(data-flow="column") 21 | header 22 | a(href="#-") Core 23 | 24 | table 25 | thead 26 | th Name 27 | th Description 28 | tbody 29 | -------------------------------------------------------------------------------- /app/targets/drupal/drupal-8/install-new-modules/install-new-modules.styl: -------------------------------------------------------------------------------- 1 | body 2 | width 600px 3 | height 380px 4 | background #333 5 | color white 6 | padding 0 1em 7 | 8 | a 9 | text-decoration none 10 | 11 | button 12 | 13 | &.install 14 | background-color #4da5f0 15 | border 1px solid #2b69d2 16 | border-radius .7em 17 | color #fff 18 | padding .5em 1em .5em .7em 19 | 20 | &::before 21 | content "+" 22 | display inline-block 23 | font-weight bold 24 | margin-right .5em 25 | 26 | p 27 | margin .5em 0 28 | 29 | h2 30 | align-items center 31 | color #fff 32 | display flex 33 | font-weight normal 34 | margin .4em 0 35 | 36 | &::after 37 | border 1px solid #fff 38 | border-radius 50% 39 | content "+" 40 | display inline-block 41 | font-size 14px 42 | font-weight bold 43 | height 1em 44 | line-height .8 45 | margin 0 .4em 46 | text-align center 47 | width 1em 48 | 49 | .with-plus-icon::before 50 | content "+" 51 | display inline-block 52 | font-weight bold 53 | margin 0 .4em 54 | 55 | .modal 56 | background white 57 | color black 58 | padding 1.5em 2em 59 | 60 | .nav 61 | align-items center 62 | margin-bottom 1em 63 | 64 | .item + .item::before 65 | content "»" 66 | display inline-block 67 | margin 0 .4em 68 | 69 | .modules 70 | border 1px solid #dadada 71 | font-family sans-serif 72 | padding-bottom 4em 73 | margin-top .5em 74 | 75 | header 76 | font-size 1.2em 77 | font-weight bold 78 | padding .3em .8em 79 | 80 | table 81 | width 100% 82 | 83 | thead, tr 84 | background-color #eee 85 | 86 | th, td 87 | border 1px solid #fff 88 | padding .5em 1em 89 | text-align left 90 | -------------------------------------------------------------------------------- /app/targets/drupal/drupal-8/navigate-to-modules/index.js: -------------------------------------------------------------------------------- 1 | import template from "./navigate-to-modules.pug" 2 | import stylesheet from "./navigate-to-modules.styl" 3 | 4 | import BaseScreenshot from "components/base-screenshot" 5 | 6 | export default class Screenshot extends BaseScreenshot { 7 | static template = template; 8 | static stylesheet = stylesheet; 9 | } 10 | -------------------------------------------------------------------------------- /app/targets/drupal/drupal-8/navigate-to-modules/navigate-to-modules.pug: -------------------------------------------------------------------------------- 1 | .screenshot 2 | .menu 3 | .item Content 4 | .item Structure 5 | .item Appearance 6 | .item People 7 | .item.focal-point.relative-arrow(data-arrow="left") Extend 8 | .item Configuration 9 | .item People 10 | 11 | .content 12 | h1 Administration 13 | -------------------------------------------------------------------------------- /app/targets/drupal/drupal-8/navigate-to-modules/navigate-to-modules.styl: -------------------------------------------------------------------------------- 1 | body 2 | width 660px 3 | height 110px 4 | 5 | .menu 6 | align-items center 7 | flex-flow row wrap 8 | background #fff 9 | color #555 10 | 11 | &.sub 12 | background-color #666 13 | 14 | .item 15 | border-left 1px solid transparent 16 | line-height 1.5 17 | padding .3em .8em 18 | 19 | & + .item 20 | border-left-color #ccc 21 | 22 | .content 23 | background-color #e0e0d8 24 | padding 0 1em 25 | -------------------------------------------------------------------------------- /app/targets/drupal/drupal-8/upload-module/index.js: -------------------------------------------------------------------------------- 1 | import template from "./upload-modules.pug" 2 | import stylesheet from "./upload-modules.styl" 3 | 4 | import BaseScreenshot from "components/base-screenshot" 5 | 6 | export default class Screenshot extends BaseScreenshot { 7 | static template = template; 8 | static stylesheet = stylesheet; 9 | } 10 | -------------------------------------------------------------------------------- /app/targets/drupal/drupal-8/upload-module/upload-modules.pug: -------------------------------------------------------------------------------- 1 | .screenshot 2 | h2 Extend 3 | 4 | .modal(data-flow="column") 5 | .nav 6 | .item 7 | a(href="#-") Home 8 | .item 9 | a(href="#-") Administration 10 | .item 11 | a(href="#-") Modules 12 | 13 | .instructions(data-flow="column") 14 | p 15 | | You can find modules and themes on drupal.org 16 | 17 | p 18 | | The following extensions are supported:  19 | i tar tgz bz2 zip 20 | 21 | p 22 | strong Upload a module or theme archive to install 23 | 24 | p 25 | .upload(data-arrow="right") 26 | input.focal-point(type="file") 27 | 28 | .hint For example:  29 | i name.tar.zip 30 | |  from your local computer 31 | 32 | footer(data-arrow="right") 33 | button.focal-point Install 34 | -------------------------------------------------------------------------------- /app/targets/drupal/drupal-8/upload-module/upload-modules.styl: -------------------------------------------------------------------------------- 1 | body 2 | width 600px 3 | height 350px 4 | background #333 5 | color white 6 | padding 0 1em 7 | 8 | a 9 | text-decoration none 10 | 11 | p 12 | margin .5em 0 13 | 14 | button 15 | background-color #ededed 16 | border none 17 | border-radius 1em 18 | font-family serif 19 | line-height 2 20 | padding 0 .8em 21 | 22 | h2 23 | align-items center 24 | color #fff 25 | display flex 26 | font-weight normal 27 | margin .4em 0 28 | 29 | &::after 30 | border 1px solid #fff 31 | border-radius 50% 32 | content "+" 33 | display inline-block 34 | font-size 14px 35 | font-weight bold 36 | height 1em 37 | line-height .8 38 | margin 0 .4em 39 | text-align center 40 | width 1em 41 | 42 | input[type="file"] 43 | width 14em 44 | 45 | .modal 46 | background white 47 | color black 48 | padding 1.5em 2em 49 | 50 | .nav 51 | align-items center 52 | margin-bottom 1em 53 | 54 | .item 55 | & + .item::before 56 | margin 0 .4em 57 | display inline-block 58 | content "»" 59 | 60 | -------------------------------------------------------------------------------- /app/targets/drupal/drupal.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/targets/drupal/index.js: -------------------------------------------------------------------------------- 1 | import drupal7 from "./drupal-7" 2 | import drupal8 from "./drupal-8" 3 | import icon from "./drupal.svg" 4 | 5 | import BaseTarget from "components/base-target" 6 | 7 | export default class DrupalTarget extends BaseTarget { 8 | static icon = icon; 9 | static id = "drupal"; 10 | static label = "Drupal"; 11 | static supports = {embedCode: true, plugin: true, insertInto: {body: true}}; 12 | static versions = [ 13 | drupal8, 14 | drupal7 15 | ]; 16 | } 17 | -------------------------------------------------------------------------------- /app/targets/drupal/upload-plugin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/embed-box/14e8488bf334bb34038a4129d39d6ecd32078179/app/targets/drupal/upload-plugin.png -------------------------------------------------------------------------------- /app/targets/generic/generic-latest/generic-latest.pug: -------------------------------------------------------------------------------- 1 | ol.steps 2 | li 3 | h2 Copy the code to your site’s <#{this.location}> tag. 4 | 5 | .copy-container(data-ref="copyContainers[]") 6 | button.button.primary.run(data-ref="copyButtons[]") Copy 7 | div.copyable(contenteditable)= this.copyText 8 | 9 | figure(data-ref="screenshotMounts[]" data-screenshot="installScript") 10 | 11 | li 12 | h2 Visit your site. 13 | 14 | p After saving the changes you made, visit your site in the browser. 15 | p You’re done! 16 | -------------------------------------------------------------------------------- /app/targets/generic/generic-latest/index.js: -------------------------------------------------------------------------------- 1 | import template from "./generic-latest.pug" 2 | import installScript from "./install-script" 3 | 4 | export default { 5 | id: "latest", 6 | template, 7 | screenshots: {installScript} 8 | } 9 | -------------------------------------------------------------------------------- /app/targets/generic/generic-latest/install-script/index.js: -------------------------------------------------------------------------------- 1 | import template from "./install-script.pug" 2 | import stylesheet from "./install-script.styl" 3 | 4 | import BaseScreenshot from "components/base-screenshot" 5 | 6 | export default class Screenshot extends BaseScreenshot { 7 | static template = template; 8 | static stylesheet = stylesheet; 9 | 10 | componentDidMount(target) { 11 | const {body} = this.iframe.contentDocument 12 | const escaper = this.iframe.contentDocument.createElement("textarea") 13 | 14 | escaper.textContent = target.copyText 15 | const escapedText = `
${escaper.innerHTML}
` 16 | 17 | body.innerHTML = body.innerHTML.replace(/\{\{EMBED_CODE_SLOT\}\}/g, escapedText) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /app/targets/generic/generic-latest/install-script/install-script.pug: -------------------------------------------------------------------------------- 1 | .screenshot 2 | if this.location === "head" 3 | :marked 4 | ```html 5 | 6 | 7 | 8 | 9 | Your website 10 | {{EMBED_CODE_SLOT}} 11 | 12 | 13 | 14 | 15 | 16 | ``` 17 | else 18 | :marked 19 | ```html 20 | 21 | 22 | 23 | 24 | Your website 25 | 26 | 27 | 28 | {{EMBED_CODE_SLOT}} 29 | 30 | 31 | ``` 32 | -------------------------------------------------------------------------------- /app/targets/generic/generic-latest/install-script/install-script.styl: -------------------------------------------------------------------------------- 1 | body 2 | width 720px 3 | height 240px 4 | 5 | pre 6 | min-height 100vh 7 | -------------------------------------------------------------------------------- /app/targets/generic/index.js: -------------------------------------------------------------------------------- 1 | import genericLatest from "./generic-latest" 2 | 3 | import BaseTarget from "components/base-target" 4 | 5 | export default class GenericTarget extends BaseTarget { 6 | static id = "generic"; 7 | static label = "Any other site"; 8 | static supports = {embedCode: true, insertInto: {head: true, body: true}}; 9 | static versions = [genericLatest]; 10 | 11 | get headerTitle() { 12 | return this.title 13 | } 14 | 15 | get title() { 16 | return `Installing ${this.store.name}.` 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /app/targets/index.js: -------------------------------------------------------------------------------- 1 | export drupal from "./drupal" 2 | export generic from "./generic" 3 | export joomla from "./joomla" 4 | export shopify from "./shopify" 5 | export squarespace from "./squarespace" 6 | export tumblr from "./tumblr" 7 | export weebly from "./weebly" 8 | export wordpress from "./wordpress" 9 | -------------------------------------------------------------------------------- /app/targets/joomla/activate-plugin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/embed-box/14e8488bf334bb34038a4129d39d6ecd32078179/app/targets/joomla/activate-plugin.png -------------------------------------------------------------------------------- /app/targets/joomla/choose-file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/embed-box/14e8488bf334bb34038a4129d39d6ecd32078179/app/targets/joomla/choose-file.png -------------------------------------------------------------------------------- /app/targets/joomla/choose-template.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/embed-box/14e8488bf334bb34038a4129d39d6ecd32078179/app/targets/joomla/choose-template.png -------------------------------------------------------------------------------- /app/targets/joomla/index.js: -------------------------------------------------------------------------------- 1 | import joomla3_6_x from "./joomla-3-6-x.pug" 2 | import icon from "./joomla.svg" 3 | 4 | import BaseTarget from "components/base-target" 5 | 6 | export default class JoomlaTarget extends BaseTarget { 7 | static icon = icon; 8 | static id = "joomla"; 9 | static label = "Joomla"; 10 | static supports = {embedCode: true, plugin: true, insertInto: {head: true, body: true}}; 11 | static versions = [{id: "3.6.x", template: joomla3_6_x}]; 12 | } 13 | -------------------------------------------------------------------------------- /app/targets/joomla/insert-code-body.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/embed-box/14e8488bf334bb34038a4129d39d6ecd32078179/app/targets/joomla/insert-code-body.png -------------------------------------------------------------------------------- /app/targets/joomla/insert-code-head.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/embed-box/14e8488bf334bb34038a4129d39d6ecd32078179/app/targets/joomla/insert-code-head.png -------------------------------------------------------------------------------- /app/targets/joomla/joomla-3-6-x.pug: -------------------------------------------------------------------------------- 1 | include ../../components/base-screenshot/mixin-annotation-arrow.pug 2 | 3 | ol.steps 4 | if this.pluginURL 5 | li 6 | != this.renderDownloadLink() 7 | p After downloading, don’t unzip the file. 8 | 9 | li 10 | h2 Upload the plugin to your Joomla Admin site 11 | 12 | figure 13 | img(src=asset(require("./upload-plugin.png"))) 14 | +annotation-arrow("nw")(style={top: "37.4%", left: "14.1%", width: "12.8%"}) 15 | +annotation-arrow("ne")(style={top: "67.5%", left: "56.8%", width: "10%"}) 16 | 17 | p In your Joomla Admin, navigate to: Extensions Install Upload Package File. 18 | p Click Choose File and select the file you just downloaded. 19 | 20 | li 21 | h2 Activate the plugin and view your site 22 | 23 | figure 24 | img(src=asset(require("./activate-plugin.png"))) 25 | +annotation-arrow("en")(style={top: "48.2%", left: "14.6%", width: "15.8%"}) 26 | +annotation-arrow("wn")(style={top: "79%", left: "50%", width: "14.1%"}) 27 | 28 | p On the Extensions Manage page, search for #{config.name ? "“" + config.name + "”" : "the plugin"}. 29 | p When you’ve found the plugin, click the red × to enable the extension. 30 | p Congrats, the installation is done! 31 | 32 | else 33 | li 34 | h2 In the Admin area of your Joomla site, navigate to: Extensions Templates Templates. 35 | 36 | figure 37 | img(src=asset(require("./open-templates.png"))) 38 | +annotation-arrow("nw")(style={top: "41.9%", left: "78.4%", width: "12%"}, transform="rotate(60deg)") 39 | 40 | li 41 | h2 Choose the template which is currently being used to power your site. 42 | p If you’re not sure which template this is you can add this embed code to all of your templates by repeating this process. 43 | 44 | figure 45 | img(src=asset(require("./choose-template.png"))) 46 | +annotation-arrow("nw")(style={top: "66.8%", left: "66.3%", width: "12%"} transform="scale(-1, 1) rotate(60deg)") 47 | 48 | li 49 | h2 Select the index.php file. 50 | 51 | figure 52 | img(src=asset(require("./choose-file.png"))) 53 | +annotation-arrow("wn")(style={top: "80.5%", left: "24.1%", width: "24.7%"}) 54 | 55 | li 56 | h2 Copy the code to your site’s <#{this.location}> tag. 57 | 58 | .copy-container(data-ref="copyContainers[]") 59 | button.button.primary.run(data-ref="copyButtons[]") Copy 60 | div.copyable(contenteditable)= this.copyText 61 | 62 | if this.location === "head" 63 | p 64 | | Carefully search for the <head> tag. 65 | | There will be other similar tags, but you only want the one with that exact name. 66 | | It should be near the beginning of the file. Insert the embed code just after that tag. 67 | 68 | figure 69 | img(src=asset(require("./insert-code-head.png"))) 70 | +annotation-arrow("ws")(style={top: "40.9%", left: "44%", width: "17.7%"}) 71 | 72 | else 73 | p 74 | | Carefully search for the </body> tag. 75 | | There will be other similar tags, but you only want the one with that exact name. 76 | | It should be near the end of the file. 77 | | Insert the embed code just before that tag. 78 | 79 | figure 80 | img(src=asset(require("./insert-code-body.png"))) 81 | +annotation-arrow("wn")(style={top: "78.1%", left: "44%", width: "18.3%"}) 82 | 83 | li 84 | h2 Click Save & Close. 85 | 86 | figure 87 | img(src=asset(require("./save.png"))) 88 | +annotation-arrow("nw")(style={top: "36.6%", left: "31%", width: "14.3%"} transform="scale(-1, 1) rotate(60deg)") 89 | 90 | p You’re done! 91 | -------------------------------------------------------------------------------- /app/targets/joomla/joomla.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/targets/joomla/open-templates.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/embed-box/14e8488bf334bb34038a4129d39d6ecd32078179/app/targets/joomla/open-templates.png -------------------------------------------------------------------------------- /app/targets/joomla/save.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/embed-box/14e8488bf334bb34038a4129d39d6ecd32078179/app/targets/joomla/save.png -------------------------------------------------------------------------------- /app/targets/joomla/upload-plugin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/embed-box/14e8488bf334bb34038a4129d39d6ecd32078179/app/targets/joomla/upload-plugin.png -------------------------------------------------------------------------------- /app/targets/shopify/index.js: -------------------------------------------------------------------------------- 1 | import shopifyLatest from "./shopify-latest" 2 | import icon from "./shopify.svg" 3 | 4 | import BaseTarget from "components/base-target" 5 | 6 | export default class ShopifyTarget extends BaseTarget { 7 | static icon = icon; 8 | static id = "shopify"; 9 | static label = "Shopify"; 10 | static supports = {embedCode: true, insertInto: {head: true, body: true}}; 11 | static versions = [shopifyLatest]; 12 | } 13 | -------------------------------------------------------------------------------- /app/targets/shopify/shopify-latest/choose-template.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/embed-box/14e8488bf334bb34038a4129d39d6ecd32078179/app/targets/shopify/shopify-latest/choose-template.png -------------------------------------------------------------------------------- /app/targets/shopify/shopify-latest/edit-template.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/embed-box/14e8488bf334bb34038a4129d39d6ecd32078179/app/targets/shopify/shopify-latest/edit-template.png -------------------------------------------------------------------------------- /app/targets/shopify/shopify-latest/index.js: -------------------------------------------------------------------------------- 1 | import template from "./shopify-latest.pug" 2 | import installScript from "./install-script" 3 | 4 | export default { 5 | id: "latest", 6 | template, 7 | screenshots: {installScript} 8 | } 9 | -------------------------------------------------------------------------------- /app/targets/shopify/shopify-latest/install-script/index.js: -------------------------------------------------------------------------------- 1 | import template from "./install-script.pug" 2 | import stylesheet from "./install-script.styl" 3 | 4 | import BaseScreenshot from "components/base-screenshot" 5 | 6 | export default class Screenshot extends BaseScreenshot { 7 | static template = template; 8 | static stylesheet = stylesheet; 9 | 10 | componentDidMount(target) { 11 | const {body} = this.iframe.contentDocument 12 | const escaper = this.iframe.contentDocument.createElement("textarea") 13 | 14 | escaper.textContent = target.copyText 15 | const escapedText = `
${escaper.innerHTML}
` 16 | 17 | body.innerHTML = body.innerHTML.replace(/\{\{EMBED_CODE_SLOT\}\}/g, escapedText) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /app/targets/shopify/shopify-latest/install-script/install-script.pug: -------------------------------------------------------------------------------- 1 | .screenshot 2 | if this.location === "head" 3 | //- Django is the closest highlighting to Shopify's Liquid templates. 4 | :marked 5 | ```django 6 | 7 | 8 | 9 | 10 | 11 | 12 | {{EMBED_CODE_SLOT}} 13 | 14 | 15 | 16 | {% include 'header-bar' %} 17 | 18 | 19 | ``` 20 | else 21 | :marked 22 | ```django 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | {{EMBED_CODE_SLOT}} 33 | 34 | {% include 'header-bar' %} 35 | 36 | 37 | ``` 38 | -------------------------------------------------------------------------------- /app/targets/shopify/shopify-latest/install-script/install-script.styl: -------------------------------------------------------------------------------- 1 | body 2 | width 700px 3 | height 300px 4 | 5 | pre 6 | min-height 100vh 7 | -------------------------------------------------------------------------------- /app/targets/shopify/shopify-latest/shopify-latest.pug: -------------------------------------------------------------------------------- 1 | include ../../../components/base-screenshot/mixin-annotation-arrow.pug 2 | 3 | ol.steps 4 | li 5 | h2 Login to the Shopify store editor. 6 | 7 | li 8 | h2 Navigate to Online Store Themes Edit HTML/CSS. 9 | p 10 | | In the left pane, click Online Store. 11 | | Click the [...] button in the header. 12 | 13 | p Then click Edit HTML/CSS in the menu that appears. 14 | 15 | figure 16 | img(src=asset(require("./edit-template.png"))) 17 | +annotation-arrow("nw")(style={top: "57%", left: "35.4%", width: "12%"} transform="rotate(60deg)") 18 | +annotation-arrow("ne")(style={top: "21%", left: "32.4%", width: "11%"} transform="rotate(41deg)") 19 | 20 | li 21 | p In the center column under Layout, Click theme.liquid. 22 | 23 | figure 24 | img(src=asset(require("./choose-template.png"))) 25 | +annotation-arrow("nw")(style={top: "48%", left: "35%", width: "16%"} transform="rotate(135deg)") 26 | 27 | li 28 | h2 Copy the code below. 29 | 30 | .copy-container(data-ref="copyContainers[]") 31 | button.button.primary.run(data-ref="copyButtons[]") Copy 32 | div.copyable(contenteditable)= this.copyText 33 | 34 | p Paste this code into your site’s <#{this.location}> tag. 35 | 36 | figure(data-ref="screenshotMounts[]" data-screenshot="installScript") 37 | 38 | li 39 | h2 Visit your site. 40 | 41 | p After saving the changes you made, visit your site in the browser. 42 | p You’re done! 43 | -------------------------------------------------------------------------------- /app/targets/shopify/shopify.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/targets/squarespace/index.js: -------------------------------------------------------------------------------- 1 | import squarespaceLatest from "./squarespace-latest" 2 | import icon from "./squarespace.svg" 3 | 4 | import BaseTarget from "components/base-target" 5 | 6 | export default class SquarespaceTarget extends BaseTarget { 7 | static icon = icon; 8 | static id = "squarespace"; 9 | static label = "Squarespace"; 10 | static supports = {embedCode: true, insertInto: {head: true, body: true}}; 11 | static versions = [squarespaceLatest]; 12 | } 13 | -------------------------------------------------------------------------------- /app/targets/squarespace/squarespace-latest/index.js: -------------------------------------------------------------------------------- 1 | import template from "./squarespace-latest.pug" 2 | import installScript from "./install-script" 3 | 4 | export default { 5 | id: "latest", 6 | template, 7 | screenshots: {installScript} 8 | } 9 | -------------------------------------------------------------------------------- /app/targets/squarespace/squarespace-latest/install-script/index.js: -------------------------------------------------------------------------------- 1 | import template from "./install-script.pug" 2 | import stylesheet from "./install-script.styl" 3 | 4 | import BaseScreenshot from "components/base-screenshot" 5 | 6 | export default class Screenshot extends BaseScreenshot { 7 | static template = template; 8 | static stylesheet = stylesheet; 9 | 10 | componentDidMount(target) { 11 | const {body} = this.iframe.contentDocument 12 | const escaper = this.iframe.contentDocument.createElement("textarea") 13 | 14 | escaper.textContent = target.copyText 15 | const escapedText = `
${escaper.innerHTML}
` 16 | 17 | body.innerHTML = body.innerHTML.replace(/\{\{EMBED_CODE_SLOT\}\}/g, escapedText) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /app/targets/squarespace/squarespace-latest/install-script/install-script.pug: -------------------------------------------------------------------------------- 1 | .screenshot 2 | h1 CODE INJECTION 3 | 4 | if this.location === "head" 5 | p Enter code that will be injected into the 'head' tag on every page of your site. 6 | 7 | else 8 | p Enter code that will be injected into the template-defined footer on every page of your site. 9 | 10 | pre 11 | code= this.copyText 12 | -------------------------------------------------------------------------------- /app/targets/squarespace/squarespace-latest/install-script/install-script.styl: -------------------------------------------------------------------------------- 1 | body 2 | height 200px 3 | width 740px 4 | background #f2f2f2 5 | color #3e3e3e 6 | font-family "Gotham SSm A", "Gotham SSm B", "Gotham SSm", "Proxima Nova", "Open Sans", "Helvetica Neue", "Helvetica", "Arial", sans-serif 7 | padding 30px 8 | overflow hidden 9 | 10 | .screenshot 11 | 12 | h1 13 | margin 0 14 | font-weight 500 15 | 16 | p 17 | color #797979 18 | 19 | pre 20 | border-left .6em #ddd solid 21 | -------------------------------------------------------------------------------- /app/targets/squarespace/squarespace-latest/squarespace-latest.pug: -------------------------------------------------------------------------------- 1 | ol.steps 2 | li 3 | h2 Login to the Squarespace site editor. 4 | 5 | li 6 | h2 Navigate to Settings Advanced Code Injection. 7 | p 8 | | In the left pane, click Settings. 9 | | Scroll to the Website section and click Advanced. 10 | | Then click Code Injection. 11 | 12 | li 13 | h2 Copy the code below. 14 | 15 | .copy-container(data-ref="copyContainers[]") 16 | button.button.primary.run(data-ref="copyButtons[]") Copy 17 | div.copyable(contenteditable)= this.copyText 18 | 19 | p Paste it into the #{this.location === "head" ? "Header" : "Footer"} box within the Code Injection section. 20 | 21 | figure(data-ref="screenshotMounts[]" data-screenshot="installScript") 22 | 23 | li 24 | h2 Visit your site. 25 | 26 | p After saving the changes you made, visit your site in the browser. 27 | p You’re done! 28 | -------------------------------------------------------------------------------- /app/targets/squarespace/squarespace.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/targets/tumblr/index.js: -------------------------------------------------------------------------------- 1 | import tumblrLatest from "./tumblr-latest" 2 | import icon from "./tumblr.svg" 3 | 4 | import BaseTarget from "components/base-target" 5 | 6 | export default class TumblrTarget extends BaseTarget { 7 | static icon = icon; 8 | static id = "tumblr"; 9 | static label = "Tumblr"; 10 | static supports = {embedCode: true, insertInto: {head: true, body: true}}; 11 | static versions = [tumblrLatest]; 12 | } 13 | -------------------------------------------------------------------------------- /app/targets/tumblr/tumblr-latest/edit-appearance.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/embed-box/14e8488bf334bb34038a4129d39d6ecd32078179/app/targets/tumblr/tumblr-latest/edit-appearance.png -------------------------------------------------------------------------------- /app/targets/tumblr/tumblr-latest/edit-html.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/embed-box/14e8488bf334bb34038a4129d39d6ecd32078179/app/targets/tumblr/tumblr-latest/edit-html.png -------------------------------------------------------------------------------- /app/targets/tumblr/tumblr-latest/edit-theme.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/embed-box/14e8488bf334bb34038a4129d39d6ecd32078179/app/targets/tumblr/tumblr-latest/edit-theme.png -------------------------------------------------------------------------------- /app/targets/tumblr/tumblr-latest/index.js: -------------------------------------------------------------------------------- 1 | import template from "./tumblr-latest.pug" 2 | import installScript from "./install-script" 3 | 4 | export default { 5 | id: "latest", 6 | template, 7 | screenshots: {installScript} 8 | } 9 | -------------------------------------------------------------------------------- /app/targets/tumblr/tumblr-latest/install-script/index.js: -------------------------------------------------------------------------------- 1 | import template from "./install-script.pug" 2 | import stylesheet from "./install-script.styl" 3 | 4 | import BaseScreenshot from "components/base-screenshot" 5 | 6 | export default class Screenshot extends BaseScreenshot { 7 | static template = template; 8 | static stylesheet = stylesheet; 9 | 10 | componentDidMount(target) { 11 | const {body} = this.iframe.contentDocument 12 | const escaper = this.iframe.contentDocument.createElement("textarea") 13 | 14 | escaper.textContent = target.copyText 15 | const escapedText = `
${escaper.innerHTML}
` 16 | 17 | body.innerHTML = body.innerHTML.replace(/\{\{EMBED_CODE_SLOT\}\}/g, escapedText) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /app/targets/tumblr/tumblr-latest/install-script/install-script.pug: -------------------------------------------------------------------------------- 1 | .screenshot 2 | if this.location === "head" 3 | :marked 4 | ```django 5 | 6 | 7 | 8 | {{EMBED_CODE_SLOT}} 9 | {Title}{block:SearchPage} ({lang:Search results for SearchQuery}){/block:SearchPage}{block:PermalinkPage}{block:PostSummary} — {PostSummary}{/block:PostSummary}{/block:PermalinkPage} 10 | 11 | 12 | 13 | 14 | 15 | 16 | {block:IfShowBarOnTop}
{/block:IfShowBarOnTop} 17 |
18 |
19 | 20 | 21 | ``` 22 | else 23 | :marked 24 | ```django 25 | 26 | 27 | 28 | {Title}{block:SearchPage} ({lang:Search results for SearchQuery}){/block:SearchPage}{block:PermalinkPage}{block:PostSummary} — {PostSummary}{/block:PostSummary}{/block:PermalinkPage} 29 | 30 | 31 | 32 | 33 | 34 | 35 | {{EMBED_CODE_SLOT}} 36 | {block:IfShowBarOnTop}
{/block:IfShowBarOnTop} 37 |
38 |
39 | 40 | 41 | ``` 42 | -------------------------------------------------------------------------------- /app/targets/tumblr/tumblr-latest/install-script/install-script.styl: -------------------------------------------------------------------------------- 1 | body 2 | width 700px 3 | height 455px 4 | 5 | pre 6 | min-height 100vh 7 | -------------------------------------------------------------------------------- /app/targets/tumblr/tumblr-latest/tumblr-latest.pug: -------------------------------------------------------------------------------- 1 | include ../../../components/base-screenshot/mixin-annotation-arrow.pug 2 | 3 | ol.steps 4 | li 5 | h2 Login to the Tumblr Dashboard. 6 | 7 | li 8 | h2 Navigate to Edit appearance Edit Theme Edit HTML. 9 | p 10 | | In the top right menu bar, click the user icon, then Edit appearance. 11 | 12 | p Then click Edit HTML/CSS in the menu that appears. 13 | 14 | figure 15 | img(src=asset(require("./edit-appearance.png"))) 16 | +annotation-arrow("ne")(style={top: "-3%", left: "47%", width: "19%"} transform="rotate(41deg)") 17 | +annotation-arrow("nw")(style={top: "76%", left: "33%", width: "18%"} transform="rotate(135deg)") 18 | 19 | li 20 | p In the center column, click Edit Theme. 21 | 22 | figure 23 | img(src=asset(require("./edit-theme.png"))) 24 | +annotation-arrow("sw")(style={top: "45%", left: "46%", width: "20%"}) 25 | 26 | li 27 | p On the top left, click Edit HTML. 28 | 29 | figure 30 | img(src=asset(require("./edit-html.png"))) 31 | +annotation-arrow("nw")(style={top: "47%", left: "44%", width: "20%"} transform="rotate(17deg)") 32 | 33 | li 34 | h2 Copy the code below. 35 | 36 | .copy-container(data-ref="copyContainers[]") 37 | button.button.primary.run(data-ref="copyButtons[]") Copy 38 | div.copyable(contenteditable)= this.copyText 39 | 40 | p Paste this code into your site’s <#{this.location}> tag. 41 | 42 | figure(data-ref="screenshotMounts[]" data-screenshot="installScript") 43 | 44 | li 45 | h2 Save your changes. 46 | 47 | p Clicking Update Preview and Save. 48 | p You’re done! 49 | -------------------------------------------------------------------------------- /app/targets/tumblr/tumblr.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/targets/weebly/index.js: -------------------------------------------------------------------------------- 1 | import weeblyLatest from "./weebly-latest.pug" 2 | import icon from "./weebly.svg" 3 | 4 | import BaseTarget from "components/base-target" 5 | 6 | export default class WeeblyTarget extends BaseTarget { 7 | static icon = icon; 8 | static id = "weebly"; 9 | static label = "Weebly"; 10 | static supports = {embedCode: true, insertInto: {head: true, body: true}}; 11 | static versions = [{id: "Latest", template: weeblyLatest}]; 12 | } 13 | -------------------------------------------------------------------------------- /app/targets/weebly/paste-embed-code-footer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/embed-box/14e8488bf334bb34038a4129d39d6ecd32078179/app/targets/weebly/paste-embed-code-footer.png -------------------------------------------------------------------------------- /app/targets/weebly/paste-embed-code-header.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/embed-box/14e8488bf334bb34038a4129d39d6ecd32078179/app/targets/weebly/paste-embed-code-header.png -------------------------------------------------------------------------------- /app/targets/weebly/weebly-latest.pug: -------------------------------------------------------------------------------- 1 | include ../../components/base-screenshot/mixin-annotation-arrow.pug 2 | 3 | ol.steps 4 | li 5 | h2 Open the Weebly Editor. 6 | 7 | p Visit Weebly Home and choose Edit Site. 8 | 9 | p If you cannot find that, try navigating directly to the Weebly Editor. 10 | 11 | li 12 | h2 From the Weebly Editor, navigate to Settings SEO. 13 | 14 | p 15 | | In the bar at the top of the page, choose Settings. 16 | | From the gray navigation menu on the left, choose SEO. 17 | 18 | li 19 | h2 20 | span Copy the code below and paste it into your site’s #{this.location === "head" ? "Header" : "Footer"} Code. 21 | 22 | .copy-container(data-ref="copyContainers[]") 23 | button.button.primary.run(type="button" data-ref="copyButtons[]") Copy 24 | div.copyable(contenteditable)= this.copyText 25 | 26 | figure 27 | if this.location === "head" 28 | img(src=asset(require("./paste-embed-code-header.png"))) 29 | else 30 | img(src=asset(require("./paste-embed-code-footer.png"))) 31 | 32 | +annotation-arrow('nw')(style={top: "44.1%", left: "39.2%", width: "15.8%"}) 33 | 34 | li 35 | h2 Click Save, and you’re done! 36 | -------------------------------------------------------------------------------- /app/targets/weebly/weebly.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/targets/wordpress/activate-plugin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/embed-box/14e8488bf334bb34038a4129d39d6ecd32078179/app/targets/wordpress/activate-plugin.png -------------------------------------------------------------------------------- /app/targets/wordpress/index.js: -------------------------------------------------------------------------------- 1 | import wordpress4 from "./wordpress-4.pug" 2 | import icon from "./wordpress.svg" 3 | 4 | import BaseTarget from "components/base-target" 5 | 6 | export default class WordPressTarget extends BaseTarget { 7 | static icon = icon; 8 | static id = "wordpress"; 9 | static label = "WordPress"; 10 | static supports = {embedCode: true, plugin: true, insertInto: {head: true, body: true}}; 11 | static versions = [{id: "4.x", template: wordpress4}]; 12 | } 13 | -------------------------------------------------------------------------------- /app/targets/wordpress/upload-plugin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/embed-box/14e8488bf334bb34038a4129d39d6ecd32078179/app/targets/wordpress/upload-plugin.png -------------------------------------------------------------------------------- /app/targets/wordpress/wordpress-4.pug: -------------------------------------------------------------------------------- 1 | include ../../components/base-screenshot/mixin-annotation-arrow.pug 2 | 3 | ol.steps 4 | if this.pluginURL 5 | li 6 | != this.renderDownloadLink() 7 | p After downloading, don’t unzip the file. 8 | 9 | li 10 | h2 Upload the plugin to your WordPress Admin site. 11 | 12 | figure 13 | img(src=asset(require("./upload-plugin.png"))) 14 | +annotation-arrow("nw")(style={top: "16%", left: "51.4%", width: "13%"} transform="rotate(76deg)") 15 | 16 | p In your WordPress Admin, navigate to: Plugins Add New Upload Plugin. 17 | p Click Choose File and select the file you just downloaded. 18 | 19 | li 20 | h2 Activate the plugin and view your site 21 | 22 | figure 23 | img(src=asset(require("./activate-plugin.png"))) 24 | +annotation-arrow("se")(style={top: "35%", left: "46%", width: "12%"} transform="rotate(87deg)") 25 | 26 | 27 | p Click Activate Plugin. 28 | p After it activates you’ll see a welcome message letting you know the installation was successful! 29 | 30 | else 31 | li 32 | h2 In your WordPress Admin, navigate to: Appearance Editor. 33 | 34 | p Navigate to the Theme Editor from the menu on the left side. 35 | 36 | li 37 | h2 Copy the code to your site’s <#{this.location}> tag. 38 | 39 | .copy-container(data-ref="copyContainers[]") 40 | button.button.primary.run(type="button" data-ref="copyButtons[]") Copy 41 | div.copyable(contenteditable)= this.copyText 42 | 43 | if this.location === "head" 44 | p Locate the header.php file from the menu on the right side. 45 | 46 | p 47 | | Carefully search for the <head> tag. 48 | | There will be other similar tags, but you only want the one with that exact name. 49 | | It should be near the beginning of the file. Insert the embed code just after that tag. 50 | 51 | else 52 | p Locate the footer.php file from the menu on the right side. 53 | 54 | p 55 | | Carefully search for the </body> tag. 56 | | There will be other similar tags, but you only want the one with that exact name. 57 | | It should be near the end of the file. 58 | | Insert the embed code just before that tag. 59 | li 60 | h2 Click Update File. 61 | 62 | p You’re done! 63 | -------------------------------------------------------------------------------- /app/targets/wordpress/wordpress.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "embed-box", 3 | "version": "2.0.3", 4 | "ignore": [ 5 | "deploy.yaml", 6 | "circle.yml", 7 | "webpack.config.js", 8 | "webpack.site.js", 9 | "test/", 10 | "media/", 11 | "scripts/", 12 | "examples/", 13 | "app/site/" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /circle.yml: -------------------------------------------------------------------------------- 1 | machine: 2 | node: 3 | version: v5.4.0 4 | 5 | dependencies: 6 | cache_directories: 7 | - "~/nvm/v5.4.0/lib/node_modules" 8 | - "~/nvm/v5.4.0/lib/bin" 9 | - "~/.npm" 10 | - "cache" 11 | 12 | post: 13 | - npm run build-site 14 | - curl https://s3.amazonaws.com/stout-builds/install | sh 15 | 16 | test: 17 | override: 18 | - echo "No tests!" 19 | 20 | deployment: 21 | production: 22 | branch: master 23 | commands: 24 | - stout deploy --env production --key $ACCESS_KEY_ID --secret $ACCESS_KEY_SECRET 25 | -------------------------------------------------------------------------------- /custom-target.js: -------------------------------------------------------------------------------- 1 | /* eslint-env node, es6 */ 2 | module.exports = require("./dist/embed-box-custom-target") 3 | -------------------------------------------------------------------------------- /custom.js: -------------------------------------------------------------------------------- 1 | /* eslint-env node, es6 */ 2 | module.exports = require("./dist/embed-box-custom") 3 | -------------------------------------------------------------------------------- /deploy.yaml: -------------------------------------------------------------------------------- 1 | default: 2 | root: 'site-deploy' 3 | 4 | production: 5 | bucket: 'embedbox.io' 6 | -------------------------------------------------------------------------------- /dist/assets.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/embed-box/14e8488bf334bb34038a4129d39d6ecd32078179/dist/assets.zip -------------------------------------------------------------------------------- /dist/assets/app/targets/joomla/activate-plugin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/embed-box/14e8488bf334bb34038a4129d39d6ecd32078179/dist/assets/app/targets/joomla/activate-plugin.png -------------------------------------------------------------------------------- /dist/assets/app/targets/joomla/choose-file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/embed-box/14e8488bf334bb34038a4129d39d6ecd32078179/dist/assets/app/targets/joomla/choose-file.png -------------------------------------------------------------------------------- /dist/assets/app/targets/joomla/choose-template.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/embed-box/14e8488bf334bb34038a4129d39d6ecd32078179/dist/assets/app/targets/joomla/choose-template.png -------------------------------------------------------------------------------- /dist/assets/app/targets/joomla/insert-code-body.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/embed-box/14e8488bf334bb34038a4129d39d6ecd32078179/dist/assets/app/targets/joomla/insert-code-body.png -------------------------------------------------------------------------------- /dist/assets/app/targets/joomla/insert-code-head.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/embed-box/14e8488bf334bb34038a4129d39d6ecd32078179/dist/assets/app/targets/joomla/insert-code-head.png -------------------------------------------------------------------------------- /dist/assets/app/targets/joomla/open-templates.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/embed-box/14e8488bf334bb34038a4129d39d6ecd32078179/dist/assets/app/targets/joomla/open-templates.png -------------------------------------------------------------------------------- /dist/assets/app/targets/joomla/save.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/embed-box/14e8488bf334bb34038a4129d39d6ecd32078179/dist/assets/app/targets/joomla/save.png -------------------------------------------------------------------------------- /dist/assets/app/targets/joomla/upload-plugin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/embed-box/14e8488bf334bb34038a4129d39d6ecd32078179/dist/assets/app/targets/joomla/upload-plugin.png -------------------------------------------------------------------------------- /dist/assets/app/targets/shopify/shopify-latest/choose-template.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/embed-box/14e8488bf334bb34038a4129d39d6ecd32078179/dist/assets/app/targets/shopify/shopify-latest/choose-template.png -------------------------------------------------------------------------------- /dist/assets/app/targets/shopify/shopify-latest/edit-template.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/embed-box/14e8488bf334bb34038a4129d39d6ecd32078179/dist/assets/app/targets/shopify/shopify-latest/edit-template.png -------------------------------------------------------------------------------- /dist/assets/app/targets/tumblr/tumblr-latest/edit-appearance.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/embed-box/14e8488bf334bb34038a4129d39d6ecd32078179/dist/assets/app/targets/tumblr/tumblr-latest/edit-appearance.png -------------------------------------------------------------------------------- /dist/assets/app/targets/tumblr/tumblr-latest/edit-html.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/embed-box/14e8488bf334bb34038a4129d39d6ecd32078179/dist/assets/app/targets/tumblr/tumblr-latest/edit-html.png -------------------------------------------------------------------------------- /dist/assets/app/targets/tumblr/tumblr-latest/edit-theme.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/embed-box/14e8488bf334bb34038a4129d39d6ecd32078179/dist/assets/app/targets/tumblr/tumblr-latest/edit-theme.png -------------------------------------------------------------------------------- /dist/assets/app/targets/weebly/paste-embed-code-footer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/embed-box/14e8488bf334bb34038a4129d39d6ecd32078179/dist/assets/app/targets/weebly/paste-embed-code-footer.png -------------------------------------------------------------------------------- /dist/assets/app/targets/weebly/paste-embed-code-header.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/embed-box/14e8488bf334bb34038a4129d39d6ecd32078179/dist/assets/app/targets/weebly/paste-embed-code-header.png -------------------------------------------------------------------------------- /dist/assets/app/targets/wordpress/activate-plugin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/embed-box/14e8488bf334bb34038a4129d39d6ecd32078179/dist/assets/app/targets/wordpress/activate-plugin.png -------------------------------------------------------------------------------- /dist/assets/app/targets/wordpress/upload-plugin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/embed-box/14e8488bf334bb34038a4129d39d6ecd32078179/dist/assets/app/targets/wordpress/upload-plugin.png -------------------------------------------------------------------------------- /docs/design-architecture.md: -------------------------------------------------------------------------------- 1 | # Design Architecture 2 | 3 | The internal design of EmbedBox focuses on two goals in particular. 4 | 5 | 1. Ease of extension. 6 | 2. File size. 7 | 8 | The first is sought using components. The second is sought using our build system. 9 | 10 | EmbedBox components are similar to React components, but without the virtual DOM. 11 | Almost every UI component inherits methods from the `BaseComponent` class and mounts itself in a similar fashion. 12 | 13 | `BaseComponent` contains a collection of common component concerns. 14 | 15 | ## Component Lifecycle 16 | 17 | ## Authoring 18 | Components usually exist in their own directory along with their internal dependencies 19 | such as stylesheets, images, and templates. 20 | 21 | When creating a component the common features are: 22 | 23 | ## `component-name.styl` 24 | This file holds your component specific styles. 25 | The following elements are set to flex positioning by the inherited styles. 26 | 27 | ```styl 28 | div, footer, header, main, section 29 | display flex 30 | 31 | [data-flow="column"] 32 | flex-flow column nowrap 33 | ``` 34 | 35 | All styles should be namespaced to prevent undesired CSS inheritance. 36 | 37 | ```styl 38 | [data-component="target-search"] 39 | .title 40 | color blue 41 | 42 | .details 43 | font-size .9em 44 | ``` 45 | ## `component-name.pug` 46 | A Pug template for the static portion of the HTML. 47 | 48 | Rather than clutter the component logic with `element.querySelector(".foo-bar")` multiple times, 49 | Components templates can add the `data-ref="fooBar"` attribute to an element. 50 | 51 | ```pug 52 | section(data-flow="column" data-component="target-search" data-event-receiver) 53 | header.header(data-flow="column") 54 | label(for="search-input")= label("searchHeader") 55 | .input-wrapper(data-ref="inputWrapper") 56 | input#search-input.search( 57 | data-ref="search" 58 | placeholder=label("searchPlaceholder") 59 | spellcheck="false" 60 | tabindex="3" 61 | type="text") 62 | .search-clear( 63 | data-ref="searchClear" 64 | tabindex="3") 65 | 66 | .entries(data-flow="column" data-ref="entriesContainer") 67 | 68 | ``` 69 | 70 | The component instance can then reference the element with `this.refs.fooBar`. 71 | Append `[]` to a `data-ref` if the ref should be an array, (e.g. `data-ref="items[]`) 72 | 73 | 74 | ## `index.js` 75 | This is the heart of your component where the dependencies are imported and assigned to the class declaration. 76 | The WebPack build system will convert the template and stylesheet into resources the browser can interpret. 77 | The `BaseComponent` class does provides most of the common utilities such as inserting stylesheets or compiling templates. 78 | 79 | ```javascript 80 | import template from "./target-search.pug" 81 | import stylesheet from "./target-search.styl" 82 | 83 | import autobind from "autobind-decorator" 84 | import BaseComponent from "components/base-component" 85 | 86 | export default class TargetSearch extends BaseComponent { 87 | static template = template; 88 | static stylesheet = stylesheet; 89 | 90 | query = ""; // Instance property. 91 | 92 | @autobind // Decorator to use consistent `this` on event handlers. 93 | handleSearchInput() { 94 | const {search} = this.refs 95 | 96 | this.query = search.value.toLowerCase() 97 | } 98 | 99 | render() { 100 | this.compileTemplate() // Implemented in BaseComponent. 101 | 102 | // Refs declared in template. 103 | const {inputWrapper, search, searchClear} = this.refs 104 | 105 | search.addEventListener("input", this.handleSearchInput) 106 | 107 | return this.element // Returning the element is expected. 108 | } 109 | } 110 | ``` 111 | -------------------------------------------------------------------------------- /embed-box.js: -------------------------------------------------------------------------------- 1 | /* eslint-env node, es6 */ 2 | module.exports = require("./dist/embed-box") 3 | -------------------------------------------------------------------------------- /media/annotation-assets.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/embed-box/14e8488bf334bb34038a4129d39d6ecd32078179/media/annotation-assets.png -------------------------------------------------------------------------------- /media/annotation-assets.sketch/Data: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/embed-box/14e8488bf334bb34038a4129d39d6ecd32078179/media/annotation-assets.sketch/Data -------------------------------------------------------------------------------- /media/annotation-assets.sketch/QuickLook/Preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/embed-box/14e8488bf334bb34038a4129d39d6ecd32078179/media/annotation-assets.sketch/QuickLook/Preview.png -------------------------------------------------------------------------------- /media/annotation-assets.sketch/QuickLook/Thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/embed-box/14e8488bf334bb34038a4129d39d6ecd32078179/media/annotation-assets.sketch/QuickLook/Thumbnail.png -------------------------------------------------------------------------------- /media/annotation-assets.sketch/metadata: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | app 6 | com.bohemiancoding.sketch 7 | build 8 | 5370 9 | commit 10 | 38aeabf36c76d40a8ed2d256f8f3b9492c3dac07 11 | fonts 12 | 13 | length 14 | 592072 15 | version 16 | 18 17 | 18 | 19 | -------------------------------------------------------------------------------- /media/annotation-assets.sketch/version: -------------------------------------------------------------------------------- 1 | 18 -------------------------------------------------------------------------------- /media/customize-feature/assets/blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/embed-box/14e8488bf334bb34038a4129d39d6ecd32078179/media/customize-feature/assets/blue.png -------------------------------------------------------------------------------- /media/customize-feature/assets/green.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/embed-box/14e8488bf334bb34038a4129d39d6ecd32078179/media/customize-feature/assets/green.png -------------------------------------------------------------------------------- /media/customize-feature/assets/orange.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/embed-box/14e8488bf334bb34038a4129d39d6ecd32078179/media/customize-feature/assets/orange.png -------------------------------------------------------------------------------- /media/customize-feature/assets/purple.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/embed-box/14e8488bf334bb34038a4129d39d6ecd32078179/media/customize-feature/assets/purple.png -------------------------------------------------------------------------------- /media/customize-feature/assets/red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/embed-box/14e8488bf334bb34038a4129d39d6ecd32078179/media/customize-feature/assets/red.png -------------------------------------------------------------------------------- /media/customize-feature/customize-feature.sketch/Data: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/embed-box/14e8488bf334bb34038a4129d39d6ecd32078179/media/customize-feature/customize-feature.sketch/Data -------------------------------------------------------------------------------- /media/customize-feature/customize-feature.sketch/QuickLook/Preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/embed-box/14e8488bf334bb34038a4129d39d6ecd32078179/media/customize-feature/customize-feature.sketch/QuickLook/Preview.png -------------------------------------------------------------------------------- /media/customize-feature/customize-feature.sketch/QuickLook/Thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/embed-box/14e8488bf334bb34038a4129d39d6ecd32078179/media/customize-feature/customize-feature.sketch/QuickLook/Thumbnail.png -------------------------------------------------------------------------------- /media/customize-feature/customize-feature.sketch/metadata: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | app 6 | com.bohemiancoding.sketch 7 | build 8 | 5370 9 | commit 10 | 38aeabf36c76d40a8ed2d256f8f3b9492c3dac07 11 | fonts 12 | 13 | length 14 | 389378 15 | version 16 | 18 17 | 18 | 19 | -------------------------------------------------------------------------------- /media/customize-feature/customize-feature.sketch/version: -------------------------------------------------------------------------------- 1 | 18 -------------------------------------------------------------------------------- /media/favicon.sketch/Data: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/embed-box/14e8488bf334bb34038a4129d39d6ecd32078179/media/favicon.sketch/Data -------------------------------------------------------------------------------- /media/favicon.sketch/QuickLook/Preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/embed-box/14e8488bf334bb34038a4129d39d6ecd32078179/media/favicon.sketch/QuickLook/Preview.png -------------------------------------------------------------------------------- /media/favicon.sketch/QuickLook/Thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/embed-box/14e8488bf334bb34038a4129d39d6ecd32078179/media/favicon.sketch/QuickLook/Thumbnail.png -------------------------------------------------------------------------------- /media/favicon.sketch/metadata: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | app 6 | com.bohemiancoding.sketch 7 | build 8 | 5370 9 | commit 10 | 38aeabf36c76d40a8ed2d256f8f3b9492c3dac07 11 | fonts 12 | 13 | length 14 | 10126 15 | version 16 | 18 17 | 18 | 19 | -------------------------------------------------------------------------------- /media/favicon.sketch/version: -------------------------------------------------------------------------------- 1 | 18 -------------------------------------------------------------------------------- /media/generic.sketch/Data: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/embed-box/14e8488bf334bb34038a4129d39d6ecd32078179/media/generic.sketch/Data -------------------------------------------------------------------------------- /media/generic.sketch/QuickLook/Preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/embed-box/14e8488bf334bb34038a4129d39d6ecd32078179/media/generic.sketch/QuickLook/Preview.png -------------------------------------------------------------------------------- /media/generic.sketch/QuickLook/Thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/embed-box/14e8488bf334bb34038a4129d39d6ecd32078179/media/generic.sketch/QuickLook/Thumbnail.png -------------------------------------------------------------------------------- /media/generic.sketch/metadata: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | app 6 | com.bohemiancoding.sketch 7 | build 8 | 5370 9 | commit 10 | 38aeabf36c76d40a8ed2d256f8f3b9492c3dac07 11 | fonts 12 | 13 | length 14 | 49128 15 | version 16 | 18 17 | 18 | 19 | -------------------------------------------------------------------------------- /media/generic.sketch/version: -------------------------------------------------------------------------------- 1 | 18 -------------------------------------------------------------------------------- /media/icons.sketch: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/embed-box/14e8488bf334bb34038a4129d39d6ecd32078179/media/icons.sketch -------------------------------------------------------------------------------- /media/logo-alt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/embed-box/14e8488bf334bb34038a4129d39d6ecd32078179/media/logo-alt.png -------------------------------------------------------------------------------- /media/logo-alt.sketch: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/embed-box/14e8488bf334bb34038a4129d39d6ecd32078179/media/logo-alt.sketch -------------------------------------------------------------------------------- /media/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/embed-box/14e8488bf334bb34038a4129d39d6ecd32078179/media/logo.png -------------------------------------------------------------------------------- /media/logo.sketch/Data: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/embed-box/14e8488bf334bb34038a4129d39d6ecd32078179/media/logo.sketch/Data -------------------------------------------------------------------------------- /media/logo.sketch/QuickLook/Preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/embed-box/14e8488bf334bb34038a4129d39d6ecd32078179/media/logo.sketch/QuickLook/Preview.png -------------------------------------------------------------------------------- /media/logo.sketch/QuickLook/Thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/embed-box/14e8488bf334bb34038a4129d39d6ecd32078179/media/logo.sketch/QuickLook/Thumbnail.png -------------------------------------------------------------------------------- /media/logo.sketch/metadata: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | app 6 | com.bohemiancoding.sketch 7 | build 8 | 5370 9 | commit 10 | 38aeabf36c76d40a8ed2d256f8f3b9492c3dac07 11 | fonts 12 | 13 | length 14 | 13244 15 | version 16 | 18 17 | 18 | 19 | -------------------------------------------------------------------------------- /media/logo.sketch/version: -------------------------------------------------------------------------------- 1 | 18 -------------------------------------------------------------------------------- /media/shopify-icon.sketch/Data: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/embed-box/14e8488bf334bb34038a4129d39d6ecd32078179/media/shopify-icon.sketch/Data -------------------------------------------------------------------------------- /media/shopify-icon.sketch/QuickLook/Preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/embed-box/14e8488bf334bb34038a4129d39d6ecd32078179/media/shopify-icon.sketch/QuickLook/Preview.png -------------------------------------------------------------------------------- /media/shopify-icon.sketch/QuickLook/Thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/embed-box/14e8488bf334bb34038a4129d39d6ecd32078179/media/shopify-icon.sketch/QuickLook/Thumbnail.png -------------------------------------------------------------------------------- /media/shopify-icon.sketch/metadata: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | app 6 | com.bohemiancoding.sketch 7 | build 8 | 5370 9 | commit 10 | 38aeabf36c76d40a8ed2d256f8f3b9492c3dac07 11 | fonts 12 | 13 | length 14 | 51192 15 | version 16 | 18 17 | 18 | 19 | -------------------------------------------------------------------------------- /media/shopify-icon.sketch/version: -------------------------------------------------------------------------------- 1 | 18 -------------------------------------------------------------------------------- /modules/custom-target.js: -------------------------------------------------------------------------------- 1 | /* eslint-env node, es6 */ 2 | const BaseTarget = require("../app/components/base-target").default 3 | 4 | module.exports = BaseTarget 5 | -------------------------------------------------------------------------------- /modules/custom.js: -------------------------------------------------------------------------------- 1 | /* eslint-env node, es6 */ 2 | 3 | const EmbedBoxBase = require("../app/embed-box-base").default 4 | 5 | EmbedBoxBase.fetchedTargets = [] 6 | 7 | module.exports = EmbedBoxBase 8 | -------------------------------------------------------------------------------- /modules/embed-box.js: -------------------------------------------------------------------------------- 1 | /* eslint-env node, es6 */ 2 | 3 | const EmbedBoxBase = require("../app/embed-box-base").default 4 | const targets = require("../app/targets") 5 | const targetOrder = [ 6 | "wordpress", 7 | "shopify", 8 | "squarespace", 9 | "tumblr", 10 | "weebly", 11 | "drupal", 12 | "joomla", 13 | "generic" 14 | ] 15 | 16 | EmbedBoxBase.fetchedTargets = targetOrder.map(id => targets[id]) 17 | 18 | module.exports = EmbedBoxBase 19 | -------------------------------------------------------------------------------- /modules/index.js: -------------------------------------------------------------------------------- 1 | /* eslint-env node */ 2 | 3 | const base = "./modules/" 4 | 5 | const entries = { 6 | "embed-box": { 7 | library: "EmbedBox", 8 | path: base + "embed-box.js" 9 | }, 10 | "embed-box-custom": { 11 | library: "EmbedBoxCustom", 12 | path: base + "custom.js" 13 | }, 14 | "embed-box-custom-target": { 15 | library: "EmbedBoxCustomTarget", 16 | path: base + "custom-target.js" 17 | } 18 | } 19 | 20 | exports.entries = entries 21 | 22 | exports.IDs = Object.keys(exports.entries) 23 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "embed-box", 3 | "version": "2.0.3", 4 | "license": "MIT", 5 | "author": "Eager", 6 | "homepage": "https://github.com/EagerIO/EmbedBox", 7 | "keywords": [ 8 | "UI", 9 | "embed", 10 | "CMS", 11 | "plugin" 12 | ], 13 | "engines": { 14 | "node": ">=5" 15 | }, 16 | "description": "Simple install guidance for CMS plugins", 17 | "repository": { 18 | "type": "git", 19 | "url": "git://github.com/EagerIO/EmbedBox.git" 20 | }, 21 | "githubPath": "EagerIO/EmbedBox", 22 | "scripts": { 23 | "start": "babel-node scripts/watch.js", 24 | "build-dist": "NODE_ENV=production babel-node scripts/build-dist.js", 25 | "build-site": "NODE_ENV=production babel-node scripts/build-site.js", 26 | "lint": "eslint ./app", 27 | "lint:fix": "eslint --fix ./app", 28 | "prepare-publish": "npm run lint && npm run build-dist", 29 | "release": "NODE_ENV=production babel-node scripts/release.js" 30 | }, 31 | "main": "embed-box.js", 32 | "dependencies": { 33 | "clipboard": "1.5.12" 34 | }, 35 | "devDependencies": { 36 | "array-from": "2.1.1", 37 | "async": "1.5.2", 38 | "autobind-decorator": "1.3.3", 39 | "autoprefixer": "6.4.0", 40 | "babel-cli": "6.11.4", 41 | "babel-core": "6.13.2", 42 | "babel-eslint": "6.1.2", 43 | "babel-loader": "6.2.4", 44 | "babel-plugin-array-includes": "2.0.3", 45 | "babel-plugin-transform-array-from": "1.0.0", 46 | "babel-plugin-transform-decorators-legacy": "1.3.4", 47 | "babel-plugin-transform-object-assign": "6.8.0", 48 | "babel-plugin-transform-proto-to-assign": "6.9.0", 49 | "babel-polyfill": "6.13.0", 50 | "babel-preset-es2015": "6.13.2", 51 | "babel-preset-stage-0": "6.5.0", 52 | "copy-webpack-plugin": "3.0.1", 53 | "css-loader": "0.23.1", 54 | "css-to-string-loader": "0.1.1", 55 | "del": "2.2.1", 56 | "eslint": "3.1.1", 57 | "eslint-loader": "1.5.0", 58 | "eslint-plugin-babel": "3.3.0", 59 | "extract-text-webpack-plugin": "2.0.0-beta.2", 60 | "file": "0.2.2", 61 | "file-loader": "0.9.0", 62 | "highlight.js": "9.5.0", 63 | "html-loader": "0.4.3", 64 | "html-webpack-plugin": "2.21.0", 65 | "jstransformer-marked": "1.0.1", 66 | "lodash.findindex": "4.6.0", 67 | "markdown-loader": "0.1.7", 68 | "marked": "0.3.5", 69 | "normalize.css": "4.2.0", 70 | "postcss-loader": "0.13.0", 71 | "pug": "2.0.0-beta5", 72 | "pug-loader": "2.2.1", 73 | "pug-walk": "0.0.3", 74 | "smooth-scroll": "0.1.4", 75 | "stickyfill": "1.1.1", 76 | "style-loader": "0.13.1", 77 | "stylus": "0.54.5", 78 | "stylus-loader": "2.2.0", 79 | "svg-inline-loader": "0.4.1", 80 | "url-loader": "0.5.7", 81 | "webpack": "2.1.0-beta.19", 82 | "webpack-dev-server": "2.1.0-beta.0", 83 | "zip-folder": "1.0.0", 84 | "zopflipng-bin": "3.0.1" 85 | }, 86 | "routes": { 87 | "development": { 88 | "hostname": "0.0.0.0", 89 | "port": 9000, 90 | "protocol": "http" 91 | }, 92 | "production": { 93 | "hostname": "embedbox.io", 94 | "port": "", 95 | "protocol": "http" 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /scripts/build-dist.js: -------------------------------------------------------------------------------- 1 | /* eslint-env node */ 2 | 3 | const baseConfig = require("../webpack.config.base")() 4 | const del = require("del") 5 | const {each, eachOfSeries} = require("async") 6 | const webpack = require("webpack") 7 | const {resolve} = require("path") 8 | const {entries, IDs} = require("../modules") 9 | const validate = require("./validate") 10 | const {spawnSync} = require("child_process") 11 | const fs = require("fs") 12 | const {walkSync} = require("file") 13 | const zopflipng = require("zopflipng-bin") 14 | const zipFolder = require("zip-folder") 15 | 16 | const ASSET_ARCHIVE_NAME = "assets.zip" 17 | 18 | const {assign} = Object 19 | const nodeTargetsDirectory = resolve(__dirname, "../targets") 20 | const outputPath = baseConfig.output.path 21 | 22 | const optimizePlugins = [ 23 | new webpack.optimize.OccurrenceOrderPlugin(true), 24 | new webpack.optimize.UglifyJsPlugin({ 25 | sourceMap: true 26 | }) 27 | ] 28 | 29 | console.log("Cleaning previous files...") 30 | del.sync(outputPath) 31 | del.sync(nodeTargetsDirectory) 32 | 33 | fs.mkdirSync(nodeTargetsDirectory) 34 | 35 | function buildEntry(id, next) { 36 | const {library, path} = entries[id] 37 | 38 | const configs = [ 39 | assign({}, baseConfig, { // Default 40 | entry: {[id]: path}, 41 | output: assign({}, baseConfig.output, { 42 | filename: `${id}.js`, 43 | library, 44 | sourceMapFilename: `${id}.map` 45 | }) 46 | }), 47 | 48 | assign({}, baseConfig, { // Optimized 49 | entry: {[id]: path}, 50 | output: assign({}, baseConfig.output, { 51 | filename: `${id}.min.js`, 52 | library, 53 | sourceMapFilename: `${id}.min.map` 54 | }), 55 | plugins: optimizePlugins.concat(baseConfig.plugins) 56 | }) 57 | ] 58 | 59 | each(configs, (config, nextConfig) => { 60 | const compiler = webpack(config) 61 | 62 | compiler.run((fatalError, stats) => { 63 | validate(fatalError, stats) 64 | 65 | console.log(`+ ${config.output.filename}`) 66 | nextConfig() 67 | }) 68 | }, next) 69 | } 70 | 71 | console.log("Building bundles...") 72 | each(IDs, buildEntry, () => { 73 | const spawnOptions = { 74 | cwd: resolve(".."), 75 | encoding: "utf8", 76 | env: process.env, 77 | stdio: [0, 1, 2] 78 | } 79 | 80 | const assetPaths = [] 81 | 82 | walkSync(resolve(__dirname, "../dist/assets"), (path, _, filenames) => { 83 | filenames.forEach(filename => assetPaths.push(`${path}/${filename}`)) 84 | }) 85 | 86 | console.log("Compressing assets... (this may take some time)") 87 | 88 | function compressAsset(path, index, next) { 89 | const {error} = spawnSync(zopflipng, ["-y", path, path], spawnOptions) 90 | 91 | if (error) throw error 92 | console.log(`+ [${index + 1}/${assetPaths.length}] ${path}`) 93 | next() 94 | } 95 | 96 | eachOfSeries(assetPaths, compressAsset, () => { 97 | zipFolder(`${outputPath}/assets/`, `${outputPath}/${ASSET_ARCHIVE_NAME}`, error => { 98 | if (error) { 99 | console.error(error) 100 | return 101 | } 102 | console.log(`+ ${ASSET_ARCHIVE_NAME}`) 103 | }) 104 | }) 105 | }) 106 | -------------------------------------------------------------------------------- /scripts/build-site.js: -------------------------------------------------------------------------------- 1 | /* eslint-env node */ 2 | 3 | const NODE_ENV = process.env.NODE_ENV || "development" 4 | const {routes} = require("../package.json") 5 | const {hostname, protocol} = routes[NODE_ENV] 6 | const siteConfig = require("../webpack.config.site") 7 | const validate = require("./validate") 8 | const webpack = require("webpack") 9 | 10 | const compiler = webpack(siteConfig) 11 | 12 | compiler.run((fatalError, stats) => { 13 | validate(fatalError, stats) 14 | 15 | console.log(`- EmbedBox Documentation ${protocol}://${hostname}`) 16 | }) 17 | -------------------------------------------------------------------------------- /scripts/release.js: -------------------------------------------------------------------------------- 1 | /* eslint-env node */ 2 | 3 | const {spawnSync} = require("child_process") 4 | const {writeFileSync} = require("fs") 5 | const packageConfig = require("../package.json") 6 | const testPackageConfig = require("../test/package.json") 7 | const bowerConfig = require("../bower.json") 8 | const resolve = require("path").resolve.bind(null, __dirname) 9 | const {argv} = process 10 | const stringify = object => JSON.stringify(object, null, 2) + "\n" 11 | const version = argv[argv.length - 1] 12 | const spawnOptions = { 13 | cwd: resolve(".."), 14 | encoding: "utf8", 15 | env: process.env, 16 | stdio: [0, 1, 2] 17 | } 18 | 19 | const configs = { 20 | "../package.json": packageConfig, 21 | "../test/package.json": testPackageConfig, 22 | "../bower.json": bowerConfig 23 | } 24 | 25 | console.log(`Upgrading version ${packageConfig.version} to ${version}`) 26 | 27 | Object 28 | .keys(configs) 29 | .forEach(path => { 30 | configs[path].version = version 31 | writeFileSync(resolve(path), stringify(configs[path])) 32 | }) 33 | 34 | const tasks = [ 35 | ["npm", ["run", "prepare-publish"]], 36 | ["git", ["add", "./dist/", "./test/package.json", "./package.json", "./bower.json"]], 37 | ["git", ["commit", `-m v${version}`]], 38 | ["git", ["tag", `v${version}`]] 39 | ] 40 | 41 | tasks.forEach(task => { 42 | const {status, error} = spawnSync(...task, spawnOptions) 43 | 44 | if (status !== 0) process.exit(status) 45 | if (error) throw error 46 | }) 47 | 48 | console.log("Done!") 49 | console.log("Publish with:") 50 | console.log("git push && git push --tags && npm publish") 51 | -------------------------------------------------------------------------------- /scripts/validate.js: -------------------------------------------------------------------------------- 1 | /* eslint-env node */ 2 | 3 | function logError(error) { 4 | console.dir(error, {depth: null, colors: true}) 5 | } 6 | 7 | module.exports = function validate(fatalError, stats) { 8 | if (fatalError) throw fatalError 9 | 10 | const {errors, warnings} = stats.toJson() 11 | 12 | if (errors.length > 0 || warnings.length > 0) { 13 | logError(warnings) 14 | logError(errors) 15 | process.exit(1) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /scripts/watch.js: -------------------------------------------------------------------------------- 1 | /* eslint-env node */ 2 | 3 | const {hostname, port, protocol} = require("../package.json").routes.development 4 | const webpack = require("webpack") 5 | const WebpackDevServer = require("webpack-dev-server") 6 | const config = require("../webpack.config.site") 7 | 8 | const server = new WebpackDevServer(webpack(config), { 9 | historyApiFallback: true, 10 | publicPath: config.output.publicPath, 11 | stats: { 12 | assets: true, 13 | chunks: false, 14 | chunkModules: false, 15 | colors: true, 16 | hash: false, 17 | timings: true, 18 | version: false 19 | } 20 | }) 21 | 22 | server.listen(port, hostname, () => { 23 | console.log(`Listening on ${protocol}://${hostname}:${port} (localhost)`) 24 | console.log("Starting server...") 25 | }) 26 | -------------------------------------------------------------------------------- /test/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | "babel-plugin-transform-decorators-legacy", 4 | "transform-object-assign", 5 | "transform-array-from", 6 | "transform-proto-to-assign" 7 | ], 8 | "presets": [["es2015", {"modules": false, "loose": true}], "stage-0"] 9 | } 10 | -------------------------------------------------------------------------------- /test/examples/custom-target.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Example Domain 6 | 7 | 8 | 9 | 10 | 52 | 53 | 54 | 55 | 84 | 85 | 86 |
87 |

Example Domain

88 |

This domain is established to be used for illustrative examples in documents. You may use this 89 | domain in examples without prior coordination or asking for permission.

90 | 91 |

92 | Embed Drift 93 | <--- Click me to get a demo of EmbedBox 94 |

95 |
96 | 97 | 98 | -------------------------------------------------------------------------------- /test/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test", 3 | "version": "2.0.3", 4 | "description": "EmbedBox test suite", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "babel-node ./watch.js" 8 | }, 9 | "author": "Eager", 10 | "private": true, 11 | "license": "MIT", 12 | "dependencies": { 13 | "babel-cli": "6.11.4", 14 | "babel-core": "6.13.2", 15 | "babel-eslint": "6.1.2", 16 | "babel-loader": "6.2.4", 17 | "babel-plugin-transform-array-from": "1.0.0", 18 | "babel-plugin-transform-decorators-legacy": "1.3.4", 19 | "babel-plugin-transform-object-assign": "6.8.0", 20 | "babel-plugin-transform-proto-to-assign": "6.9.0", 21 | "babel-polyfill": "6.13.0", 22 | "babel-preset-es2015": "6.13.2", 23 | "babel-preset-stage-0": "6.5.0", 24 | "embed-box": "1.3.1", 25 | "eslint": "3.1.1", 26 | "eslint-loader": "1.5.0", 27 | "eslint-plugin-babel": "3.3.0", 28 | "html-webpack-plugin": "2.21.0", 29 | "webpack": "2.1.0-beta.19", 30 | "webpack-dev-server": "2.1.0-beta.0" 31 | }, 32 | "routes": { 33 | "test": { 34 | "hostname": "localhost", 35 | "port": 9001, 36 | "protocol": "http" 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | import EmbedBox from "embed-box" 2 | 3 | document.addEventListener("DOMContentLoaded", () => { 4 | new EmbedBox({ 5 | name: "Example Plugin", 6 | embedCode: "" 7 | }) 8 | }) 9 | -------------------------------------------------------------------------------- /test/test.pug: -------------------------------------------------------------------------------- 1 | doctype html 2 | html(lang="en") 3 | head 4 | title= htmlWebpackPlugin.options.title 5 | 6 | meta(charset="utf-8") 7 | meta(name="viewport" content="width=device-width, initial-scale=1, user-scalable=no") 8 | 9 | body 10 | main(data-flow="column") 11 | p Hello World! 12 | -------------------------------------------------------------------------------- /test/watch.js: -------------------------------------------------------------------------------- 1 | /* eslint-env node */ 2 | 3 | const {hostname, port, protocol} = require("./package.json").routes.test 4 | const webpack = require("webpack") 5 | const WebpackDevServer = require("webpack-dev-server") 6 | const config = require("./webpack.config.test") 7 | 8 | const server = new WebpackDevServer(webpack(config), { 9 | historyApiFallback: true, 10 | publicPath: config.output.publicPath, 11 | stats: { 12 | assets: true, 13 | chunks: false, 14 | chunkModules: false, 15 | colors: true, 16 | hash: false, 17 | timings: true, 18 | version: false 19 | } 20 | }) 21 | 22 | server.listen(port, hostname, () => { 23 | console.log(`Listening on ${protocol}://${hostname}:${port}`) 24 | console.log("Starting server...") 25 | }) 26 | -------------------------------------------------------------------------------- /test/webpack.config.test.js: -------------------------------------------------------------------------------- 1 | /* eslint-env node */ 2 | "use strict" 3 | 4 | const createWebpackConfig = require("../webpack.config.base") 5 | const HtmlWebpackPlugin = require("html-webpack-plugin") 6 | 7 | module.exports = createWebpackConfig({ 8 | entry: { 9 | test: "./test.js" 10 | }, 11 | 12 | output: { 13 | filename: "[name].js", 14 | sourceMapFilename: "[name].map" 15 | }, 16 | 17 | plugins: [ 18 | new HtmlWebpackPlugin({ 19 | title: "EmbedBox Test", 20 | template: "./test.pug" 21 | }) 22 | ] 23 | }) 24 | -------------------------------------------------------------------------------- /webpack.config.base.js: -------------------------------------------------------------------------------- 1 | /* eslint-env node */ 2 | "use strict" 3 | 4 | const ENVIRONMENT = process.env.NODE_ENV || "development" 5 | const {resolve} = require("path") 6 | const {githubPath, routes, version} = require("./package.json") 7 | const {hostname, port, protocol} = routes[ENVIRONMENT] 8 | const webpack = require("webpack") 9 | const marked = require("marked") 10 | const {highlight} = require("highlight.js") 11 | const autoprefixer = require("autoprefixer") 12 | 13 | const PORT_POSTFIX = port ? `:${port}` : "" 14 | const PROJECT_URL = `${protocol}://${hostname}${PORT_POSTFIX}` 15 | const exclude = /node_modules/ 16 | const {stringify} = JSON 17 | const ASSET_CDN_URL = `https://cdn.rawgit.com/${githubPath}/v${version}` 18 | 19 | marked.setOptions({ 20 | highlight(code, language) { 21 | code = code.replace(/\{\{PROJECT_URL\}\}/g, PROJECT_URL) 22 | 23 | return highlight(language, code).value 24 | } 25 | }) 26 | 27 | const renderer = new marked.Renderer() 28 | const DIST_DIRECTORY_NAME = "dist" 29 | const ASSET_PATH = ENVIRONMENT === "development" ? PROJECT_URL : `${ASSET_CDN_URL}/${DIST_DIRECTORY_NAME}` 30 | 31 | module.exports = function createWebpackConfig(overrides = {}) { 32 | const buildDirectory = overrides.buildDirectory || DIST_DIRECTORY_NAME 33 | const {entry = {}, loaders = [], output = {}, plugins = []} = overrides 34 | const $ = {} 35 | 36 | $.buildDirectory = buildDirectory 37 | 38 | $.devtool = "source-map" 39 | 40 | $.entry = entry 41 | 42 | $.markdownLoader = {renderer} 43 | 44 | $.output = Object.assign({ 45 | path: resolve(__dirname, buildDirectory), 46 | publicPath: "/", 47 | libraryTarget: "umd", 48 | umdNamedDefine: true 49 | }, output) 50 | 51 | $.plugins = [ 52 | new webpack.NoErrorsPlugin(), 53 | new webpack.DefinePlugin({ 54 | ASSET_CDN_URL: stringify(ASSET_CDN_URL), 55 | ASSET_PATH: stringify(ASSET_PATH), 56 | VERSION: stringify(version), 57 | PROJECT_URL: stringify(PROJECT_URL), 58 | "process.env.NODE_ENV": stringify(ENVIRONMENT) 59 | }) 60 | ].concat(plugins) 61 | 62 | $.resolve = { 63 | extensions: ["", ".js", ".json"], 64 | modules: [resolve(__dirname, "app"), "node_modules"] 65 | } 66 | 67 | $.postcss = () => [autoprefixer({remove: false, browsers: ["last 2 versions", "ie 10"]})] 68 | 69 | const minimizeParam = ENVIRONMENT === "development" ? "-minimize" : "minimize" 70 | const filePathPrefix = ENVIRONMENT === "development" ? "" : "assets/" 71 | 72 | $.module = { 73 | loaders: loaders.concat([ 74 | {test: /\.md$/, loader: "html!markdown", exclude}, 75 | {test: /\.pug$/, loader: "pug", exclude}, 76 | {test: /\.png|jpe?g|gif$/i, loader: `file?name=${filePathPrefix}[path][name].[ext]`, exclude: /site/}, 77 | {test: /\.js$/, loader: "babel", exclude}, 78 | {test: /\.svg$/, loader: "svg-inline", exclude}, 79 | { 80 | test: /\.styl$/, 81 | exclude: /site/, 82 | loader: `css-to-string!css?${minimizeParam}!postcss!stylus?paths=app` 83 | } 84 | ]), 85 | noParse: /\.min\.js/ 86 | } 87 | 88 | if (ENVIRONMENT === "development") { 89 | $.devtool = "eval" 90 | 91 | $.module.preLoaders = [{ 92 | exclude, 93 | loader: "eslint-loader", 94 | test: /\.js$/ 95 | }] 96 | 97 | const devServerClient = `webpack-dev-server/client?http://0.0.0.0:${port}` 98 | 99 | if (Array.isArray($.entry)) { 100 | $.entry.unshift(devServerClient) 101 | } 102 | else { 103 | $.entry["dev-server-client"] = devServerClient 104 | } 105 | } 106 | 107 | return $ 108 | } 109 | -------------------------------------------------------------------------------- /webpack.config.site.js: -------------------------------------------------------------------------------- 1 | /* eslint-env node */ 2 | "use strict" 3 | 4 | const createWebpackConfig = require("./webpack.config.base") 5 | const HtmlWebpackPlugin = require("html-webpack-plugin") 6 | const ExtractTextPlugin = require("extract-text-webpack-plugin") 7 | const CopyWebpackPlugin = require("copy-webpack-plugin") 8 | 9 | const extractCSS = new ExtractTextPlugin("site.css") 10 | 11 | module.exports = createWebpackConfig({ 12 | // TODO: It'd be nice if this was fetched from deploy.yaml 13 | buildDirectory: "site-deploy", 14 | 15 | entry: { 16 | site: "./app/site/index.js", 17 | "embed-box": "./app/site/globals/embed-box.js", 18 | "embed-box-custom": "./app/site/globals/embed-box-custom.js", 19 | "embed-box-custom-target": "./app/site/globals/embed-box-custom-target.js", 20 | segment: "./app/site/segment.js" 21 | }, 22 | 23 | loaders: [ 24 | {test: /\.png|jpe?g|gif$/i, loader: "url?limit=0", include: /site/}, 25 | { 26 | test: /\.styl$/, 27 | include: /site/, 28 | loader: ExtractTextPlugin.extract({ 29 | notExtractLoader: "style", 30 | loader: "css!postcss!stylus?paths=app/" 31 | }) 32 | } 33 | ], 34 | 35 | output: { 36 | filename: "[name].js", 37 | sourceMapFilename: "[name].map" 38 | }, 39 | 40 | plugins: [ 41 | extractCSS, 42 | new HtmlWebpackPlugin({ 43 | title: "EmbedBox install UI by Eager", 44 | description: "An open-source UI which makes it easy for your users to install your embed code.", 45 | template: "app/site/index.pug" 46 | }), 47 | new CopyWebpackPlugin([ 48 | {from: "./app/site/assets/examples", to: "examples"} 49 | ], { 50 | ignore: [".DS_Store"] 51 | }) 52 | ] 53 | }) 54 | --------------------------------------------------------------------------------