├── .babelrc ├── .eslintrc.js ├── .gitattributes ├── .github ├── actions │ ├── create-pr.js │ └── create-survey.js ├── semantic.yml └── workflows │ ├── electron-data.yml │ └── test.yml ├── .gitignore ├── .nvmrc ├── .prettierrc ├── .stylelintrc.json ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE.md ├── README.md ├── app.json ├── cypress.json ├── cypress ├── fixtures │ └── example.json ├── integration │ └── actions.js ├── plugins │ └── index.js └── support │ ├── commands.js │ └── index.js ├── data ├── blog │ ├── README │ ├── electron-14-0.md │ └── s3-bucket-change.md ├── locale.yml ├── meetups.json ├── processes.json ├── repos-using-electron.json └── userland │ ├── dependencies.json │ ├── dev_dependencies.json │ ├── github_contributors.json │ ├── most_downloaded_packages.json │ ├── package_authors.json │ ├── package_dependencies.json │ └── starred_apps.json ├── docs ├── ci-status.md └── infrastructure.md ├── lib ├── apps.js ├── featured-apps.js ├── fiddle.js ├── i18n.js └── releases.js ├── middleware ├── browsersync.js ├── context-builder.js ├── feedback.js ├── lang-resolver.js ├── register-octicons.js ├── sass.js └── webpack.js ├── nodemon.json ├── package.json ├── public ├── bower_components │ ├── basecoat │ │ └── scss │ │ │ ├── _grid.scss │ │ │ ├── _layout.scss │ │ │ ├── _type.scss │ │ │ ├── _utility.scss │ │ │ ├── _variables.scss │ │ │ ├── mixins │ │ │ ├── _breakpoints.scss │ │ │ ├── _clearfix.scss │ │ │ ├── _grid-framework.scss │ │ │ └── _grid.scss │ │ │ └── primer-marketing.scss │ └── primer-css │ │ └── scss │ │ ├── _base.scss │ │ ├── _button-group.scss │ │ ├── _filter-list.scss │ │ ├── _form-group.scss │ │ ├── _form-select.scss │ │ ├── _input-group.scss │ │ ├── _mixins.scss │ │ ├── _type.scss │ │ ├── _variables.scss │ │ ├── primer.scss │ │ └── utilities │ │ ├── _border.scss │ │ ├── _colors.scss │ │ ├── _layout.scss │ │ ├── _margin.scss │ │ ├── _padding.scss │ │ ├── _typography.scss │ │ └── utilities.scss ├── images │ ├── Electron-Architecture.png │ ├── WebView2-Architecture.png │ ├── browser.png │ ├── cross-platform.svg │ ├── devtron-event-listeners.png │ ├── devtron-icon.svg │ ├── devtron-ipc.png │ ├── devtron-linter.png │ ├── devtron-logo.svg │ ├── devtron-require-graph.png │ ├── electron-api-demos.png │ ├── electron-icon-avatar.png │ ├── electron-icon-avatar.svg │ ├── electron-icon.png │ ├── electron-icon.svg │ ├── electron-logo.svg │ ├── favicon.ico │ ├── featured_apps │ │ ├── figma-icon.png │ │ ├── figma.png │ │ ├── figma.webp │ │ ├── invision-icon.svg │ │ ├── invision.png │ │ ├── invision.webp │ │ ├── messenger-icon.svg │ │ ├── messenger.png │ │ ├── messenger.webp │ │ ├── slack-icon.svg │ │ ├── slack.png │ │ ├── slack.webp │ │ ├── teams-icon.svg │ │ ├── teams.png │ │ ├── teams.webp │ │ ├── twitch-icon.svg │ │ ├── twitch.png │ │ ├── twitch.webp │ │ ├── vscode-icon.svg │ │ ├── vscode.png │ │ ├── vscode.webp │ │ ├── whatsapp-icon.svg │ │ ├── whatsapp.png │ │ └── whatsapp.webp │ ├── fiddle │ │ ├── code-with-types.png │ │ ├── compile-and-package.png │ │ ├── easy-start.png │ │ ├── explore-electron.png │ │ ├── fiddle-icon.svg │ │ └── fiddle-logo.svg │ ├── flow.svg │ ├── fork.png │ ├── hero-1-0.svg │ ├── hero-electron.svg │ ├── hero-hover.png │ ├── hero.png │ ├── hero.svg │ ├── open-source.svg │ ├── opengraph.png │ ├── openjsf.svg │ ├── os-box.png │ ├── userland │ │ ├── dependencies.svg │ │ ├── dev_dependencies.svg │ │ ├── github_contributors.svg │ │ ├── most_downloaded_packages.svg │ │ ├── package_authors.svg │ │ ├── package_dependencies.svg │ │ └── starred_apps.svg │ └── web-tech.svg └── styles │ ├── _app.scss │ ├── _base.scss │ ├── _blog.scss │ ├── _devtron.scss │ ├── _docs.scss │ ├── _hero.scss │ ├── _home.scss │ ├── _kb-shortcut-dialog.scss │ ├── _languages.scss │ ├── _releases.scss │ ├── _search.scss │ ├── _userland.scss │ ├── _variables.scss │ ├── _versions.scss │ ├── helpers │ ├── _code.scss │ ├── _footer.scss │ ├── _icons.scss │ ├── _navigation.scss │ ├── _page-headers.scss │ ├── _section.scss │ └── _tables.scss │ ├── hljs │ ├── github.css │ └── overrides.scss │ ├── index.scss │ ├── octicons │ ├── octicons.scss │ ├── octicons.svg │ └── octicons.ttf │ ├── ui │ ├── _governance.scss │ └── landing │ │ └── _fiddle.scss │ └── vendor │ └── devicon │ ├── LICENSE │ ├── devicon.css │ └── fonts │ ├── devicon.eot │ ├── devicon.svg │ ├── devicon.ttf │ └── devicon.woff ├── routes ├── _404.js ├── apps │ ├── index.js │ └── show.js ├── blacklivesmatter.js ├── community.js ├── devtron.js ├── docs │ ├── category.js │ ├── history.js │ ├── index.js │ ├── show.js │ └── structures.js ├── donors.js ├── feed │ ├── mainFeed.js │ └── releases.js ├── fiddle.js ├── governance │ └── index.js ├── headers.js ├── home.js ├── index.js ├── languages │ ├── index.js │ └── proxy.js ├── releases │ └── index.js └── userland │ ├── index.js │ └── show.js ├── script ├── bootstrap ├── compress-images ├── integration.sh ├── precompile-assets.js ├── release ├── server └── update-data.js ├── scripts ├── add-code-block-buttons.js ├── anchor-links.js ├── apply-active-class-to-active-links.js ├── create-filter-list.js ├── docs-api-labels.js ├── docs-language-toggle.js ├── docs-table-of-contents.js ├── expanding-versions.js ├── get-localized-strings.js ├── index.js ├── install-toggle.js ├── kb-shortcut-dialog.js ├── language-selector.js ├── lazy-load-images.js ├── links-checker.js ├── platform-specific-content.js ├── remove-scheme-from-link-text.js ├── science.js ├── screenshot-thumb-selector.js ├── service-worker.js ├── sticky-app-meta.js ├── update-app-download-links.js └── update-demo-app-download-link.js ├── server.js ├── templates ├── api.hbs ├── app.hbs ├── empty.hbs ├── index.js ├── package.hbs ├── readme.md └── tutorial.hbs ├── test ├── i18n.js ├── index.js └── localization.js ├── views ├── 404.hbs ├── apps │ ├── index.hbs │ └── show.hbs ├── blm.hbs ├── blog │ ├── index.hbs │ └── show.hbs ├── community.hbs ├── devtron.hbs ├── docs │ ├── all.hbs │ ├── api.hbs │ ├── development.hbs │ ├── history.hbs │ ├── index.hbs │ ├── show.hbs │ ├── structures.hbs │ └── tutorial.hbs ├── donors.hbs ├── fiddle.hbs ├── governance │ └── index.hbs ├── home.hbs ├── languages │ └── index.hbs ├── layouts │ ├── docs.hbs │ ├── main.hbs │ └── post.hbs ├── partials │ ├── announcement_banner.hbs │ ├── blog_byline.hbs │ ├── doc.hbs │ ├── featured_app.hbs │ ├── feedback.hbs │ ├── footer.hbs │ ├── head.hbs │ ├── header.hbs │ ├── hero.hbs │ ├── kb_shortcut_dialog.hbs │ ├── new-docs.hbs │ └── userland │ │ ├── footer.hbs │ │ └── header.hbs ├── releases │ └── index.hbs └── userland │ ├── devtron.hbs │ ├── index.hbs │ └── show.hbs ├── webpack.common.js └── yarn.lock /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@babel/preset-env", 5 | { 6 | "targets": "> 0.25%, not dead" 7 | } 8 | ] 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | parserOptions: { 3 | ecmaVersion: 2018, 4 | sourceType: 'module', 5 | }, 6 | extends: ['plugin:prettier/recommended'], 7 | ignorePatterns: ['precompiled/**/*.js'], 8 | } 9 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.github/actions/create-pr.js: -------------------------------------------------------------------------------- 1 | const { Octokit } = require('@octokit/action') 2 | 3 | const octokit = new Octokit() 4 | 5 | const [owner, repo] = process.env.GITHUB_REPOSITORY.split('/') 6 | 7 | async function main () { 8 | const prs = await octokit.pulls.list({ 9 | owner, 10 | repo, 11 | state: 'open', 12 | head: `${owner}:update-data` 13 | }) 14 | 15 | if (prs.data.length === 0) { 16 | const pr = await octokit.pulls.create({ 17 | owner, 18 | repo, 19 | title: 'build(deps): update electron data packages', 20 | base: 'master', 21 | head: 'update-data', 22 | body: 'Auto-update from GitHub Actions.', 23 | maintainer_can_modify: true 24 | }) 25 | console.log('Pull request created:', pr.html_url) 26 | } else { 27 | console.log('Pull request updated:', prs.data[0].html_url) 28 | } 29 | } 30 | 31 | main() 32 | -------------------------------------------------------------------------------- /.github/actions/create-survey.js: -------------------------------------------------------------------------------- 1 | //@ts-check 2 | const surveyMonkey = require('../../lib/surveymonkey') 3 | const oneDay = 24 * 3600 * 1000 4 | const fourteenDays = oneDay * 14 5 | /* 6 | Because cron does not allow to say "every other Monday" we have to manually 7 | check all Mondays if there is something to do or not looking at the creation 8 | date. Most of the times it should be a Monday at midnight, but the first one 9 | might have been created at a different moment (e.g. Tuesday) so we cannot 10 | check for 14 days exactly. We use 1 week + 1 day instead 11 | */ 12 | const maxDaysRunning = 8 13 | 14 | /** @type {import('../../lib/surveymonkey').CollectorOptions} */ 15 | const collectorOptions = { 16 | status: 'open', 17 | close_date: new Date(Date.now() + fourteenDays), // Today + 14 days 18 | response_limit: 400, 19 | height: 300, 20 | width: 500, 21 | } 22 | 23 | /** 24 | * Checks if the survey has been opened for 2 weeks or more and creates a new one 25 | * @param {import('../../lib/surveymonkey').Survey} survey 26 | */ 27 | const shouldCreateNewOne = (survey) => { 28 | const days = Math.floor((survey.dateCreated.getTime() - Date.now()) / oneDay) 29 | 30 | return days >= maxDaysRunning 31 | } 32 | 33 | 34 | const start = async () => { 35 | const lastSurvey = await surveyMonkey.getLatestSurvey() 36 | 37 | if (lastSurvey.id === '-1' || !shouldCreateNewOne(lastSurvey)) { 38 | console.log(`No need to create new survey. Last survey info:`) 39 | console.log(lastSurvey) 40 | 41 | return 42 | } 43 | 44 | // TODO: Update grafana with satisfaction score and NPS data? 45 | 46 | const title = `${lastSurvey.title.split('-')[0]} - ${new Date().toLocaleDateString()}` 47 | const newSurvey = await surveyMonkey.createNewSurvey(lastSurvey.id, title) 48 | console.log(`Survey "${title}" created`) 49 | 50 | await surveyMonkey.closeCollector(lastSurvey.collectorId) 51 | 52 | const newCollector = await surveyMonkey.createCollector(newSurvey.id, lastSurvey.collectorId, collectorOptions) 53 | console.log(`Collector ${newCollector.id} associated to ${newSurvey.id}`) 54 | 55 | console.log(newCollector) 56 | } 57 | 58 | start() 59 | -------------------------------------------------------------------------------- /.github/semantic.yml: -------------------------------------------------------------------------------- 1 | # Always validate the PR title, and ignore the commits 2 | titleOnly: true 3 | -------------------------------------------------------------------------------- /.github/workflows/electron-data.yml: -------------------------------------------------------------------------------- 1 | name: Update electron-* data packages 2 | on: 3 | schedule: 4 | - cron: "0 18 * * *" 5 | 6 | jobs: 7 | updateElectronDataPackages: 8 | name: Auto-update Electron data 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@master 12 | - name: Fetch git branches 13 | run: git fetch --no-tags --prune --depth=1 origin +refs/heads/*:refs/remotes/origin/* 14 | - uses: actions/setup-node@v2.4.1 15 | with: 16 | node-version: '12.x' 17 | - run: yarn install --frozen-lockfile 18 | - name: Switch to update branch 19 | run: | 20 | if git branch --remotes | grep -q origin/update-data; then 21 | git checkout update-data 22 | else 23 | git checkout -b update-data 24 | fi 25 | - run: npm run update-data 26 | - name: Commit package update changes 27 | env: 28 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 29 | run: | 30 | echo "machine github.com login $GITHUB_ACTOR password $GITHUB_TOKEN" > ~/.netrc 31 | chmod 600 ~/.netrc 32 | git add package.json yarn.lock 33 | if test -n "$( git status -s)"; then 34 | git config user.name "$GITHUB_ACTOR" 35 | git config user.email "electron-bot@users.noreply.github.com" 36 | git diff 37 | git commit -m "build(deps): update electron data packages" 38 | git push --set-upstream origin update-data 39 | node --unhandled-rejections=strict .github/actions/create-pr.js 40 | else 41 | echo No update needed 42 | fi 43 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - master 7 | push: 8 | branches: 9 | - master 10 | 11 | jobs: 12 | unit: 13 | name: Unit Tests 14 | 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - uses: actions/checkout@v2 19 | - name: Use Node.js 14 20 | uses: actions/setup-node@v2.4.1 21 | with: 22 | node-version: 14 23 | - uses: actions/cache@v2.1.6 24 | with: 25 | path: ~/.npm 26 | key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} 27 | restore-keys: | 28 | ${{ runner.os }}-node- 29 | - run: yarn install --frozen-lockfile 30 | - run: yarn test 31 | env: 32 | CI: true 33 | 34 | integration: 35 | name: Integration Tests 36 | 37 | runs-on: ubuntu-latest 38 | 39 | steps: 40 | - uses: actions/checkout@v2 41 | - name: Use Node.js 14 42 | uses: actions/setup-node@v2.4.1 43 | with: 44 | node-version: 14 45 | - uses: actions/cache@v2.1.6 46 | with: 47 | path: ~/.npm 48 | key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} 49 | restore-keys: | 50 | ${{ runner.os }}-node- 51 | - run: yarn install --frozen-lockfile 52 | - run: yarn run integration 53 | env: 54 | CI: true 55 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | _site 2 | .sass-cache 3 | node_modules/ 4 | npm-debug.log 5 | .jekyll-metadata 6 | images/crushed 7 | .env 8 | css/**/*.css 9 | cypress/screenshots/* 10 | cypress/videos/* 11 | /precompiled/ 12 | .nyc_output 13 | coverage 14 | .DS_Store 15 | .vscode 16 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 14 2 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "trailingComma": "es5", 4 | "semi": false, 5 | "proseWrap": "always" 6 | } 7 | -------------------------------------------------------------------------------- /.stylelintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "stylelint-config-standard", 3 | "plugins": [ 4 | "stylelint-scss" 5 | ], 6 | "rules": { 7 | "at-rule-no-unknown": null, 8 | "declaration-block-single-line-max-declarations": null, 9 | "scss/at-rule-no-unknown": true 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. 6 | 7 | ## Our Standards 8 | 9 | Examples of behavior that contributes to creating a positive environment include: 10 | 11 | * Using welcoming and inclusive language 12 | * Being respectful of differing viewpoints and experiences 13 | * Gracefully accepting constructive criticism 14 | * Focusing on what is best for the community 15 | * Showing empathy towards other community members 16 | 17 | Examples of unacceptable behavior by participants include: 18 | 19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances 20 | * Trolling, insulting/derogatory comments, and personal or political attacks 21 | * Public or private harassment 22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission 23 | * Other conduct which could reasonably be considered inappropriate in a professional setting 24 | 25 | ## Our Responsibilities 26 | 27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. 28 | 29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. 30 | 31 | ## Scope 32 | 33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. 34 | 35 | ## Enforcement 36 | 37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at [coc@electronjs.org](mailto:coc@electronjs.org). All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. 38 | 39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. 40 | 41 | ## Attribution 42 | 43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] 44 | 45 | [homepage]: http://contributor-covenant.org 46 | [version]: http://contributor-covenant.org/version/1/4/ 47 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) GitHub Inc. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # electronjs.org-old 2 | 3 | > **Warning** 4 | > 5 | > This repository hosts an old version of Electron's website. For the source code of the current website, see the [`electron/website`](https://github.com/electron/website) repository. 6 | 7 | ## License 8 | 9 | [MIT](LICENSE.md) 10 | -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "electron.atom.io", 3 | "description": "", 4 | "scripts": {}, 5 | "env": { 6 | "PAPERTRAIL_API_TOKEN": { 7 | "required": true 8 | } 9 | }, 10 | "formation": {}, 11 | "addons": [ 12 | "papertrail" 13 | ], 14 | "buildpacks": [ 15 | { 16 | "url": "heroku/nodejs" 17 | } 18 | ] 19 | } -------------------------------------------------------------------------------- /cypress.json: -------------------------------------------------------------------------------- 1 | { 2 | "projectId": "4j4z3k", 3 | "requestTimeout": 10000, 4 | "record": false, 5 | "defaultCommandTimeout": 10000 6 | } 7 | -------------------------------------------------------------------------------- /cypress/fixtures/example.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Using fixtures to represent data", 3 | "email": "hello@cypress.io", 4 | "body": "Fixtures are a great way to mock data for responses to routes" 5 | } -------------------------------------------------------------------------------- /cypress/plugins/index.js: -------------------------------------------------------------------------------- 1 | // *********************************************************** 2 | // This example plugins/index.js can be used to load plugins 3 | // 4 | // You can change the location of this file or turn off loading 5 | // the plugins file with the 'pluginsFile' configuration option. 6 | // 7 | // You can read more here: 8 | // https://on.cypress.io/plugins-guide 9 | // *********************************************************** 10 | 11 | // This function is called when a project is opened or re-opened (e.g. due to 12 | // the project's config changing) 13 | 14 | module.exports = (on, config) => { 15 | // `on` is used to hook into various events Cypress emits 16 | // `config` is the resolved Cypress config 17 | } 18 | -------------------------------------------------------------------------------- /cypress/support/commands.js: -------------------------------------------------------------------------------- 1 | // *********************************************** 2 | // This example commands.js shows you how to 3 | // create various custom commands and overwrite 4 | // existing commands. 5 | // 6 | // For more comprehensive examples of custom 7 | // commands please read more here: 8 | // https://on.cypress.io/custom-commands 9 | // *********************************************** 10 | // 11 | // 12 | // -- This is a parent command -- 13 | // Cypress.Commands.add("login", (email, password) => { ... }) 14 | // 15 | // 16 | // -- This is a child command -- 17 | // Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... }) 18 | // 19 | // 20 | // -- This is a dual command -- 21 | // Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... }) 22 | // 23 | // 24 | // -- This is will overwrite an existing command -- 25 | // Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) 26 | -------------------------------------------------------------------------------- /cypress/support/index.js: -------------------------------------------------------------------------------- 1 | // *********************************************************** 2 | // This example support/index.js is processed and 3 | // loaded automatically before your test files. 4 | // 5 | // This is a great place to put global configuration and 6 | // behavior that modifies Cypress. 7 | // 8 | // You can change the location of this file or turn off 9 | // automatically serving support files with the 10 | // 'supportFile' configuration option. 11 | // 12 | // You can read more here: 13 | // https://on.cypress.io/configuration 14 | // *********************************************************** 15 | 16 | // Import commands.js using ES2015 syntax: 17 | import './commands' 18 | 19 | // Alternatively you can use CommonJS syntax: 20 | // require('./commands') 21 | -------------------------------------------------------------------------------- /data/blog/README: -------------------------------------------------------------------------------- 1 | The blog has moved. To write a new post please go to https://github.com/electron/electronjs.org-new/tree/main/blog -------------------------------------------------------------------------------- /data/blog/s3-bucket-change.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "S3 Bucket Migration" 3 | author: MarshallOfSound 4 | date: '2022-05-06' 5 | --- 6 | 7 | Electron is changing its primary S3 bucket, you may need to update your build scripts 8 | 9 | --- 10 | 11 | # What is happening? 12 | 13 | Currently a significant amount of Electrons build artifacts are uploaded to an S3 bucket called `gh-contractor-zcbenz`, as part of ongoing infrastructure / ownership migrations that started way back in 2020 we will be changing everything that used `gh-contractor-zcbenz` from it's current home in S3 to a new storage system hosted at `https://artifacts.electronjs.org`. The path prefix that most of our assets use is changing slightly as well. Examples are included below: 14 | 15 | **Before:** https://gh-contractor-zcbenz.s3.amazonaws.com/atom-shell/dist/v17.0.0/node.lib 16 | **After:** https://artifacts.electronjs.org/headers/dist/v17.0.0/node.lib 17 | 18 | The important things here are the **Hostname** changed and the `/atom-shell` **prefix** changed. Another example, this time for debug symbols: 19 | 20 | **Before:** https://gh-contractor-zcbenz.s3.amazonaws.com/atom-shell/symbols/path/to/symbol.pdb 21 | **After:** https://artifacts.electronjs.org/symbols/path/to/symbol.pdb 22 | 23 | Again, the hostname changed and the `/atom-shell` prefix was changed. 24 | 25 | # How might this impact you? 26 | 27 | For anyone using standard build tooling such as `electron-rebuild`, `electron-packager` or `@electron/get` you won't have to do anything, this should be the majority of people. 28 | 29 | For anyone directly referencing the S3 bucket, you must update your reference to point at the hostname and update the path as well. 30 | 31 | # What about existing data? 32 | 33 | Most data that existed on the `gh-contractor-zcbenz` bucket has been cloned into the new storage system. This means all debug symbols and all headers have been copied. If you relied on some data in that bucket that hasn't been copied over please raise an issue in [`electron/electron`](https://github.com/electron/electron) and let us know. 34 | 35 | The current `gh-contractor-zcbenz` S3 bucket will not be actively deleted however we can't guarantee how long that bucket will be left alive. We **strongly** reccomend updating to target the new bucket as soon as possible. 36 | -------------------------------------------------------------------------------- /data/meetups.json: -------------------------------------------------------------------------------- 1 | [{ 2 | "name": "Bay Area Electron User Group", 3 | "location": "San Francisco, California", 4 | "country": "USA", 5 | "href": "http://www.meetup.com/Bay-Area-Electron-User-Group" 6 | }, 7 | { 8 | "name": "Electron Korea", 9 | "location": "Seoul", 10 | "country": "South Korea", 11 | "href": "https://electron-kr.github.io/electron-kr" 12 | }, 13 | { 14 | "name": "Austin ElectronJS Meetup", 15 | "location": "Austin, Texas", 16 | "country": "USA", 17 | "href": "http://www.meetup.com/Austin-ElectronJs-Meetup" 18 | }, 19 | { 20 | "name": "Github Electron Bamenda", 21 | "location": "Bamenda", 22 | "country": "Cameroon", 23 | "href": "mailto:mathalpha26@gmail.com" 24 | }, 25 | { 26 | "name": "Pittsburgh Video Game Developers: Electron Games Topic", 27 | "location": "Pittsburgh, PA", 28 | "country": "USA", 29 | "href": "https://www.meetup.com/Pittsburgh-Game-Dev/" 30 | } 31 | ] 32 | -------------------------------------------------------------------------------- /data/processes.json: -------------------------------------------------------------------------------- 1 | { 2 | "Accelerator": "Main", 3 | "app": "Main", 4 | "autoUpdater": "Main", 5 | "BrowserWindow": "Main", 6 | "BrowserWindowProxy": "Renderer", 7 | "ClientRequest": "Main", 8 | "Certificate Object": "Main", 9 | "clipboard": "Main and Renderer", 10 | "Cookies": "Main", 11 | "contentTracing": "Main", 12 | "crashReporter": "Main and Renderer", 13 | "Debugger": "Main", 14 | "desktopCapturer": "Renderer", 15 | "dialog": "Main", 16 | "Display Object": "Main and Renderer", 17 | "DownloadItem": "Main", 18 | "Environment Variables": "Main and Renderer", 19 | "File Object": "Renderer", 20 | "Frameless Window": "Main", 21 | "globalShortcut": "Main", 22 | "IncomingMessage": "Main", 23 | "ipcMain": "Main", 24 | "ipcRenderer": "Renderer", 25 | "JumpListCategory Object": "Main", 26 | "JumpListItem Object": "Main", 27 | "Locales": "Main", 28 | "MemoryUsageDetails Object": "Renderer", 29 | "MenuItem": "Main", 30 | "Menu": "Main", 31 | "nativeImage": "Main and Renderer", 32 | "net": "Main", 33 | "powerMonitor": "Main", 34 | "powerSaveBlocker": "Main", 35 | "process": "Main and Renderer", 36 | "protocol": "Main", 37 | "Rectangle Object": "Main and Renderer", 38 | "remote": "Renderer", 39 | "screen": "Main and Renderer", 40 | "session": "Main", 41 | "shell": "Main and Renderer", 42 | "ShortcutDetails Object": "Main and Renderer", 43 | "Synopsis": "Main and Renderer", 44 | "Supported Chrome Command Line Switches": "Main", 45 | "systemPreferences": "Main", 46 | "Task Object": "Main", 47 | "ThumbarButton Object": "Main", 48 | "TouchBar": "Main", 49 | "TouchBarButton": "Main", 50 | "TouchBarColorPicker": "Main", 51 | "TouchBarGroup": "Main", 52 | "TouchBarLabel": "Main", 53 | "TouchBarPopover": "Main", 54 | "TouchBarScrubber": "Main", 55 | "TouchBarSegmentedControl": "Main", 56 | "TouchBarSlider": "Main", 57 | "TouchBarSpacer": "Main", 58 | "Tray": "Main", 59 | "webContents": "Main", 60 | "webFrame": "Renderer", 61 | "WebRequest": "Main", 62 | "<webview> Tag": "Renderer", 63 | "window.open Function": "Renderer" 64 | } 65 | -------------------------------------------------------------------------------- /docs/ci-status.md: -------------------------------------------------------------------------------- 1 | # CI Status across Website Infrastructure 2 | 3 | This document contains status badges for all CI tasks related to [electronjs.org](https://electronjs.org). See status checks for default CI builds as well as scheduled cron jobs. 4 | 5 | ## Builds 6 | 7 | | Repository | Status | 8 | | ---------------- | -------------------------------------------------------------------------------------------------------------------- | 9 | | `electronjs.org` | ![Test](https://github.com/electron/electronjs.org/workflows/Test/badge.svg?branch=master) | 10 | | `i18n` | ![CI / GitHub Actions](https://github.com/electron/i18n/workflows/CI%20/%20GitHub%20Actions/badge.svg?branch=master) | 11 | | `apps` | ![Continous Integration](https://github.com/electron/apps/workflows/Continous%20Integration/badge.svg?branch=master) | 12 | | `releases` | ![Test](https://github.com/electron/releases/workflows/Test/badge.svg?branch=master) | 13 | 14 | ## Crons 15 | 16 | | Repository | Status | 17 | | ---------- | -------------------------------------------------------------------------------------------------------- | 18 | | `i18n` | ![Auto-merge Crowdin PR](https://github.com/electron/i18n/workflows/Auto-merge%20Crowdin%20PR/badge.svg) | 19 | | `i18n` | ![Update source content](https://github.com/electron/i18n/workflows/Update%20source%20content/badge.svg) | 20 | | `apps` | ![Update and release](https://github.com/electron/apps/workflows/Update%20and%20release/badge.svg) | 21 | | `releases` | ![Update And Release](https://github.com/electron/releases/workflows/Update%20And%20Release/badge.svg) | 22 | -------------------------------------------------------------------------------- /lib/apps.js: -------------------------------------------------------------------------------- 1 | const apps = require('electron-apps').sort( 2 | (a, b) => new Date(b.date) - new Date(a.date) 3 | ) 4 | 5 | module.exports = apps 6 | -------------------------------------------------------------------------------- /lib/featured-apps.js: -------------------------------------------------------------------------------- 1 | const developer = [ 2 | { 3 | name: 'Visual Studio Code', 4 | screenshot: 'vscode', 5 | url: 'https://code.visualstudio.com/', 6 | icon: 'vscode-icon.svg', 7 | }, 8 | ] 9 | 10 | const messenger = [ 11 | { 12 | name: 'Facebook Messenger', 13 | screenshot: 'messenger', 14 | url: 'https://www.messenger.com/desktop', 15 | icon: 'messenger-icon.svg', 16 | }, 17 | { 18 | name: 'WhatsApp', 19 | screenshot: 'whatsapp', 20 | url: 'https://www.whatsapp.com', 21 | icon: 'whatsapp-icon.svg', 22 | }, 23 | ] 24 | 25 | const collaboration = [ 26 | { 27 | name: 'Slack', 28 | screenshot: 'slack', 29 | url: 'https://slack.com', 30 | icon: 'slack-icon.svg', 31 | }, 32 | { 33 | name: 'Microsoft Teams', 34 | screenshot: 'teams', 35 | url: 'https://products.office.com/en-US/microsoft-teams/group-chat-software', 36 | icon: 'teams-icon.svg', 37 | }, 38 | ] 39 | 40 | const entertainment = [ 41 | { 42 | name: 'Twitch', 43 | screenshot: 'twitch', 44 | url: 'https://twitch.com', 45 | icon: 'twitch-icon.svg', 46 | }, 47 | ] 48 | 49 | const design = [ 50 | { 51 | name: 'Figma', 52 | screenshot: 'figma', 53 | url: 'https://figma.com', 54 | icon: 'figma-icon.png', 55 | }, 56 | { 57 | name: 'InVision', 58 | screenshot: 'invision', 59 | url: 'https://invisionapp.com', 60 | icon: 'invision-icon.svg', 61 | }, 62 | ] 63 | 64 | const featuredApps = { 65 | developer, 66 | messenger, 67 | entertainment, 68 | collaboration, 69 | design, 70 | } 71 | 72 | module.exports = featuredApps 73 | -------------------------------------------------------------------------------- /lib/fiddle.js: -------------------------------------------------------------------------------- 1 | const https = require('https') 2 | 3 | const RENEW_EVERY = 43200000 // 12 hours 4 | const BASIC_CACHE = { 5 | latest_version: null, 6 | timestamp: 0, 7 | } 8 | 9 | function getLatestFiddleVersion() { 10 | if ( 11 | Date.now() - RENEW_EVERY < BASIC_CACHE.timestamp && 12 | BASIC_CACHE.latest_version 13 | ) { 14 | return Promise.resolve(BASIC_CACHE.latest_version) 15 | } 16 | 17 | console.log(`Latest fiddle version in cache out of data, refetching`) 18 | 19 | return new Promise((resolve, reject) => { 20 | let data = '' 21 | 22 | const options = { 23 | hostname: 'api.github.com', 24 | port: 443, 25 | path: '/repos/electron/fiddle/releases/latest', 26 | method: 'GET', 27 | headers: { 28 | 'User-Agent': 'electronjs.org', 29 | }, 30 | } 31 | 32 | const req = https.request(options, (res) => { 33 | const url = `https://${options.hostname}${options.path}` 34 | const status = `[${res.statusCode}]: ${res.statusMessage}` 35 | console.log(`Request to ${url}: ${status}`) 36 | 37 | if (res.statusCode >= 200 && res.statusCode < 400) { 38 | res.on('data', (d) => (data += d)) 39 | 40 | res.on('end', () => { 41 | // Get the tag_name out of JSON, remove a possibly 42 | // leading "v", then resolve the promise with the 43 | // version number 44 | try { 45 | const parsedData = JSON.parse(data) 46 | 47 | if (parsedData.tag_name) { 48 | const tag = parsedData.tag_name.toString() 49 | 50 | if (tag.startsWith('v')) { 51 | BASIC_CACHE.latest_version = tag.slice(1) 52 | } else { 53 | BASIC_CACHE.latest_version = tag 54 | } 55 | 56 | BASIC_CACHE.timestamp = Date.now() 57 | 58 | resolve(BASIC_CACHE.latest_version) 59 | } 60 | } catch (error) { 61 | reject(error) 62 | } 63 | }) 64 | } 65 | }) 66 | 67 | req.on('error', (error) => { 68 | reject(error) 69 | }) 70 | 71 | req.end() 72 | }) 73 | } 74 | 75 | module.exports = { 76 | getLatestFiddleVersion: getLatestFiddleVersion, 77 | } 78 | -------------------------------------------------------------------------------- /lib/i18n.js: -------------------------------------------------------------------------------- 1 | require('require-yaml') 2 | 3 | const i18n = require('electron-i18n') 4 | const flat = require('flat') 5 | const get = require('lodash/get') 6 | const set = require('lodash/set') 7 | const locales = Object.keys(i18n.locales) 8 | const websiteStrings = require('../data/locale.yml') 9 | const websiteKeys = Object.keys(flat(websiteStrings)) 10 | const emailPattern = /[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}/gi 11 | 12 | // If any website strings are missing from electron-i18n, 13 | // fill them in with the corresponding value from ../data/locale.yml 14 | locales.forEach((locale) => { 15 | websiteKeys.forEach((key) => { 16 | const deepKey = `website.${locale}.${key}` 17 | // Always use local locale.yml data for English, 18 | // and backfill to English for missing entries in other languages. 19 | if (locale === 'en-US' || !get(i18n, deepKey)) { 20 | set(i18n, deepKey, get(websiteStrings, key)) 21 | } 22 | }) 23 | }) 24 | 25 | function containsEmail(string) { 26 | return typeof string === 'string' && string.match(emailPattern) 27 | } 28 | 29 | function obfuscate(string) { 30 | return string.replace(emailPattern, (match) => { 31 | return Array.prototype.map 32 | .call(match, (chr) => { 33 | return `&#${chr.charCodeAt(0)};` 34 | }) 35 | .join('') 36 | }) 37 | } 38 | 39 | const keys = Object.keys(flat(i18n)) 40 | 41 | keys.forEach((key) => { 42 | const value = get(i18n, key) 43 | if (containsEmail(value)) { 44 | set(i18n, key, obfuscate(value)) 45 | } 46 | }) 47 | 48 | // attempt to filter down number of translated languages. 49 | const languageAllowList = [ 50 | 'en-US', 51 | 'de-DE', 52 | 'es-ES', 53 | 'fr-FR', 54 | 'ja-JP', 55 | 'pt-BR', 56 | 'ru-RU', 57 | 'zh-CN', 58 | ] 59 | 60 | i18n.locales = Object.keys(i18n.locales) 61 | .filter((key) => languageAllowList.includes(key)) 62 | .reduce((acc, val) => { 63 | acc[val] = i18n.locales[val] 64 | return acc 65 | }, {}) 66 | 67 | module.exports = i18n 68 | i18n.languageAllowList = languageAllowList 69 | -------------------------------------------------------------------------------- /lib/releases.js: -------------------------------------------------------------------------------- 1 | const semver = require('semver') 2 | 3 | class Release { 4 | constructor(releaseData) { 5 | this.data = releaseData 6 | this.semver = semver.parse(this.data.version) 7 | } 8 | 9 | isStable() { 10 | return !this.isBeta() && !this.isAlpha() && !this.isNightly() 11 | } 12 | 13 | isBeta() { 14 | return this.semver.prerelease.includes('beta') 15 | } 16 | 17 | isAlpha() { 18 | return this.semver.prerelease.includes('alpha') 19 | } 20 | 21 | isNightly() { 22 | return this.semver.prerelease.includes('nightly') 23 | } 24 | 25 | hasNpmDistTag(tag) { 26 | if (this.data.npm_dist_tags) { 27 | return this.data.npm_dist_tags.includes(tag) 28 | } else { 29 | return false 30 | } 31 | } 32 | } 33 | 34 | class Releases { 35 | constructor(releases) { 36 | this.all = releases.map((r) => new Release(r)) 37 | 38 | // electron-releases data is already sorted in version order, 39 | // highest version to lowest. 40 | this.stableRelease = this.all.find((r) => r.hasNpmDistTag('latest')) 41 | this.betaRelease = this.all.find((r) => r.hasNpmDistTag('beta')) 42 | this.alphaRelease = this.all.find((r) => r.hasNpmDistTag('alpha')) 43 | this.nightlyRelease = this.all.find((r) => r.hasNpmDistTag('nightly')) 44 | } 45 | 46 | ofType(type) { 47 | switch (type) { 48 | case 'stable': 49 | return this.all.filter((r) => r.isStable()) 50 | case 'beta': 51 | return this.all.filter((r) => r.isBeta()) 52 | case 'alpha': 53 | return this.all.filter((r) => r.isAlpha()) 54 | case 'nightly': 55 | return this.all.filter((r) => r.isNightly()) 56 | default: 57 | throw new Error(`Invalid release type: ${type}`) 58 | } 59 | } 60 | } 61 | 62 | module.exports = Releases 63 | -------------------------------------------------------------------------------- /middleware/browsersync.js: -------------------------------------------------------------------------------- 1 | const env = require('lil-env-thing') 2 | const path = require('path') 3 | 4 | module.exports = function browsersync() { 5 | if (env.test || env.production) return noop 6 | 7 | const bs = require('browser-sync')({ 8 | port: 3030, 9 | files: [ 10 | path.join(__dirname, '../**/*.md'), 11 | path.join(__dirname, '../**/*.hbs'), 12 | // path.join(__dirname, '../**/*.scss'), 13 | path.join(__dirname, '../data/**/*'), 14 | path.join(__dirname, '../js/**/*'), 15 | ], 16 | logSnippet: false, 17 | logLevel: 'silent', 18 | }) 19 | return require('connect-browser-sync')(bs) 20 | } 21 | 22 | function noop(req, res, next) { 23 | return next() 24 | } 25 | -------------------------------------------------------------------------------- /middleware/context-builder.js: -------------------------------------------------------------------------------- 1 | const i18n = require('lib/i18n') 2 | const electronReleases = require('electron-releases') 3 | const electronLatestStableVersion = i18n.electronLatestStableTag.slice(1) 4 | const { deps } = electronReleases.find( 5 | (release) => release.version === electronLatestStableVersion 6 | ) 7 | const { getLanguageNativeName } = require('locale-code') 8 | const rtlDetect = require('rtl-detect') 9 | const Releases = require('../lib/releases') 10 | 11 | // Supply all route handlers with a baseline `req.context` object 12 | module.exports = function contextBuilder(req, res, next) { 13 | // Attach i18n object to request so any route handler can use it if needed 14 | req.i18n = i18n 15 | 16 | // This allows the language to be set per-request using a query param, so 17 | // folks can share a link like /docs/api/app?lang=fr-FR and know that 18 | // the recipient will see the doc in that language, regardless of their 19 | // language settings. If no query param is set, fall back to the default 20 | // language (or the one set in the cookie) 21 | if (req.query.lang) { 22 | req.language = req.query.lang 23 | } 24 | 25 | // If request language does not exist, fall back to English 26 | // e.g. /?lang=Foo 27 | if (!i18n.website[req.language]) req.language = 'en-US' 28 | 29 | const localized = i18n.website[req.language] 30 | 31 | // Page titles, descriptions, etc 32 | let page = Object.assign( 33 | { 34 | title: 'Electron', 35 | path: req.path, 36 | }, 37 | i18n.website[req.language].pages[req.path] 38 | ) 39 | 40 | if (req.path !== '/') { 41 | page.title = `${page.title} | Electron` 42 | } 43 | 44 | req.context = { 45 | electronLatestStableVersion, 46 | electronLatestStableTag: i18n.electronLatestStableTag, 47 | deps: deps, 48 | releases: new Releases(electronReleases), 49 | currentLocale: req.language, 50 | currentLocaleNativeName: getLanguageNativeName(req.language), 51 | languageDirection: rtlDetect.getLangDir(req.language), 52 | locales: i18n.locales, 53 | page: page, 54 | showAnnouncementBanner: true, 55 | localized: localized, 56 | cookies: req.cookies, 57 | hostname: `${req.protocol}://${req.get('host')}`, 58 | } 59 | 60 | if (req.path.startsWith('/docs')) { 61 | req.context.docs = i18n.docs[req.language] 62 | } 63 | 64 | return next() 65 | } 66 | -------------------------------------------------------------------------------- /middleware/feedback.js: -------------------------------------------------------------------------------- 1 | //@ts-check 2 | 3 | module.exports = async (req, res, next) => { 4 | const feedbackEmbedCode = process.env.feedbackEmbedCode 5 | const debugging = req.query.debug === 'true' 6 | 7 | req.context = Object.assign(req.context, { 8 | feedbackEmbedCode, 9 | debugging, 10 | }) 11 | 12 | next() 13 | } 14 | -------------------------------------------------------------------------------- /middleware/lang-resolver.js: -------------------------------------------------------------------------------- 1 | const i18n = require('../lib/i18n') 2 | const url = require('url') 3 | 4 | const locales = Object.keys(i18n.locales) 5 | 6 | var lowerLangRegion = {} 7 | var lowerLang = {} 8 | // Keep all the language/region and language in a object 9 | // with property names in lowercases to resolve the lang code 10 | locales.forEach((locale) => { 11 | // map locale in lowercase 12 | lowerLangRegion[locale.toLowerCase()] = locale 13 | 14 | const lang = locale.split('-').shift().toLowerCase() 15 | // The first lang for each locale is the default one 16 | // to resolve when the region is missing 17 | if (!lowerLang.hasOwnProperty(lang)) { 18 | lowerLang[lang] = locale 19 | } 20 | }) 21 | 22 | function resolve(lang) { 23 | var lower = lang.toLowerCase() 24 | if (lowerLangRegion.hasOwnProperty(lower)) { 25 | return lowerLangRegion[lower] 26 | } 27 | 28 | lower = lang.split('-').shift().toLowerCase() 29 | if (lowerLang.hasOwnProperty(lower)) { 30 | return lowerLang[lower] 31 | } 32 | 33 | return lang 34 | } 35 | 36 | function parseurl(req) { 37 | return url.parse(req.url) 38 | } 39 | 40 | module.exports = function langResolver(req, res, next) { 41 | if (req.query.lang) { 42 | // resolving lang to lang-REGION when 43 | // - cases does not match 44 | // - region is missing 45 | const rlang = resolve(req.query.lang) 46 | 47 | // redirect only when the resolved lang exists and it is different 48 | if (rlang && rlang !== req.query.lang) { 49 | const parsedUrl = parseurl(req) 50 | req.query.lang = rlang 51 | return res.redirect( 52 | url.format({ pathname: parsedUrl.pathname, query: req.query }) 53 | ) 54 | } 55 | } 56 | 57 | return next() 58 | } 59 | -------------------------------------------------------------------------------- /middleware/register-octicons.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | 3 | const octicons = require('@primer/octicons') 4 | 5 | /** 6 | * Helper function that accepts options (e.g. name) and returns a string 7 | * of the `` tag. 8 | * 9 | * @param {String} name The name of octicon. See https://octicons.github.com/ for search icons. 10 | * @param {String} className Add more CSS classes to the `` tag. 11 | * @param {String} width Size the SVG icon larger using `height`. 12 | * @param {String} height Size the SVG icon larger using `width`. 13 | * @param {String} ariaLabel Add accessibility `aria-label` to the icon. 14 | * @returns {Promise} Returns a string of the `` tag. 15 | */ 16 | module.exports = async function getOcticons( 17 | name, 18 | className, 19 | width, 20 | height, 21 | ariaLabel 22 | ) { 23 | // Strict Null Checking 24 | if (name === undefined || name === null) { 25 | return 26 | } 27 | 28 | const opts = { 29 | class: className || null, 30 | width: width || null, 31 | height: height || null, 32 | 'aria-label': ariaLabel || null, 33 | } 34 | 35 | if (opts.class === null) delete opts.class 36 | if (opts.width === null) delete opts.width 37 | if (opts.height === null) delete opts.height 38 | if (opts['aria-label'] === null) delete opts['aria-label'] 39 | 40 | const svg = await octicons[name].toSVG(opts) 41 | return svg 42 | } 43 | -------------------------------------------------------------------------------- /middleware/sass.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const sass = require('node-sass-middleware') 3 | 4 | module.exports = function () { 5 | return sass({ 6 | src: path.join(__dirname, '../public/styles'), 7 | response: true, 8 | debug: false, 9 | includePaths: path.join(__dirname, '../node_modules'), 10 | // outputStyle: 'compressed', 11 | prefix: '/styles', 12 | }) 13 | } 14 | -------------------------------------------------------------------------------- /middleware/webpack.js: -------------------------------------------------------------------------------- 1 | const webpack = require('webpack') 2 | const config = require('../webpack.common') 3 | const webpackDevMiddleware = require('webpack-dev-middleware') 4 | 5 | module.exports = () => { 6 | return webpackDevMiddleware(webpack(config), { 7 | publicPath: config.output.publicPath, 8 | }) 9 | } 10 | -------------------------------------------------------------------------------- /nodemon.json: -------------------------------------------------------------------------------- 1 | { 2 | "ext": "js,yml", 3 | "ignore": ["scripts/*","test/*"] 4 | } 5 | -------------------------------------------------------------------------------- /public/bower_components/basecoat/scss/_grid.scss: -------------------------------------------------------------------------------- 1 | // GRID 2 | 3 | // Container widths 4 | // 5 | // Set the container width, and override it for fixed navbars in media queries. 6 | 7 | @if $enable-grid-classes { 8 | .container { 9 | @include make-container(); 10 | @include make-container-max-widths(); 11 | max-width: container(lg); 12 | } 13 | 14 | .container-fluid { 15 | @include make-container(); 16 | } 17 | 18 | .container-narrow { 19 | @include make-container(); 20 | max-width: container(md); 21 | } 22 | 23 | .container-wide { 24 | @include make-container(); 25 | max-width: container(xl); 26 | } 27 | } 28 | 29 | // Row 30 | // 31 | // Rows contain and clear the floats of your columns. 32 | 33 | @if $enable-grid-classes { 34 | .row { 35 | @include make-row(); 36 | } 37 | } 38 | 39 | // Columns 40 | // 41 | // Common styles for small and large grid columns 42 | 43 | @if $enable-grid-classes { 44 | @include make-grid-columns(); 45 | } 46 | -------------------------------------------------------------------------------- /public/bower_components/basecoat/scss/_layout.scss: -------------------------------------------------------------------------------- 1 | // Flexible images 2 | img { 3 | max-width: 100%; 4 | height: auto; 5 | } 6 | 7 | // Pre-built Layouts 8 | 9 | // If you are against using grid classes, you can create a layout in CSS. 10 | // The below class would be marked up like this: 11 | //
12 | //
13 | //
14 | // This is the content in the main column. 15 | //
16 | // 19 | //
20 | //
21 | 22 | .layout-aside { 23 | @include make-row(); 24 | 25 | .main-col { 26 | @include make-col(12); 27 | 28 | @include breakpoint(md) { 29 | @include make-col(8); 30 | } 31 | 32 | @include breakpoint(lg) { 33 | @include make-col(9); 34 | } 35 | } 36 | .aside { 37 | @include make-col(12); 38 | 39 | @include breakpoint(md) { 40 | @include make-col(4); 41 | } 42 | 43 | @include breakpoint(lg) { 44 | @include make-col(3); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /public/bower_components/basecoat/scss/mixins/_breakpoints.scss: -------------------------------------------------------------------------------- 1 | // Breakpoint viewport sizes and media queries. 2 | // 3 | // Breakpoints are defined as a map of (name: minimum width), order from small to large: 4 | // 5 | // (xs: 0, sm: 544px, md: 768px) 6 | // 7 | // The map defined in the `$grid-breakpoints` global variable is used as the `$breakpoints` argument by default. 8 | 9 | 10 | // Minimum breakpoint width. Null for the smallest (first) breakpoint. 11 | // 12 | // >> breakpoint-min(sm, (xs: 0, sm: 544px, md: 768px)) 13 | // 544px 14 | @function breakpoint-min($name, $breakpoints: $grid-breakpoints) { 15 | $min: map-get($breakpoints, $name); 16 | @return if($min != 0, $min, null); 17 | } 18 | 19 | // Media of at least the minimum breakpoint width. No query for the smallest breakpoint. 20 | // Makes the @content apply to the given breakpoint and wider. 21 | @mixin breakpoint($name, $breakpoints: $grid-breakpoints) { 22 | $min: breakpoint-min($name, $breakpoints); 23 | @if $min { 24 | @media (min-width: $min) { 25 | @content; 26 | } 27 | } @else { 28 | @content; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /public/bower_components/basecoat/scss/mixins/_clearfix.scss: -------------------------------------------------------------------------------- 1 | @mixin clearfix() { 2 | &::after { 3 | content: ""; 4 | display: table; 5 | clear: both; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /public/bower_components/basecoat/scss/mixins/_grid-framework.scss: -------------------------------------------------------------------------------- 1 | // Framework grid generation 2 | // 3 | // Used only by Bootstrap to generate the correct number of grid classes given 4 | // any value of `$grid-columns`. 5 | 6 | @mixin make-grid-columns($columns: $grid-columns, $gutter: $grid-gutter, $breakpoints: $grid-breakpoints) { 7 | $breakpoint-counter: 0; 8 | @each $breakpoint in map-keys($breakpoints) { 9 | $breakpoint-counter: ($breakpoint-counter + 1); 10 | @include breakpoint($breakpoint, $breakpoints) { 11 | 12 | @for $i from 1 through $columns { 13 | .col-#{$breakpoint}-#{$i} { 14 | @include make-col($i, $columns); 15 | } 16 | } 17 | 18 | @each $modifier in (pull, push) { 19 | @for $i from 0 through $columns { 20 | .#{$modifier}-#{$breakpoint}-#{$i} { 21 | @include make-col-modifier($modifier, $i, $columns) 22 | } 23 | } 24 | } 25 | 26 | // `$columns - 1` because offsetting by the width of an entire row isn't possible 27 | @for $i from 0 through ($columns - 1) { 28 | @if $breakpoint-counter != 1 or $i != 0 { // Avoid emitting useless .col-xs-offset-0 29 | .offset-#{$breakpoint}-#{$i} { 30 | @include make-col-modifier(offset, $i, $columns) 31 | } 32 | } 33 | } 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /public/bower_components/basecoat/scss/mixins/_grid.scss: -------------------------------------------------------------------------------- 1 | /// Grid system 2 | // 3 | // Generate semantic grid columns with these mixins. 4 | 5 | @mixin make-container($gutter: $grid-gutter) { 6 | margin-left: auto; 7 | margin-right: auto; 8 | padding-left: ($gutter / 2); 9 | padding-right: ($gutter / 2); 10 | @include clearfix(); 11 | } 12 | 13 | // For each breakpoint, define the maximum width of the container in a media query 14 | @mixin make-container-max-widths($max-widths: $container-max-widths, $breakpoints: $grid-breakpoints) { 15 | @each $breakpoint, $container-max-width in $max-widths { 16 | @include breakpoint($breakpoint, $breakpoints) { 17 | max-width: $container-max-width; 18 | } 19 | } 20 | } 21 | 22 | @mixin make-row($gutter: $grid-gutter) { 23 | @include clearfix(); 24 | margin-left: ($gutter / -2); 25 | margin-right: ($gutter / -2); 26 | } 27 | 28 | @mixin make-col($size, $columns: $grid-columns) { 29 | position: relative; 30 | min-height: 1px; 31 | padding-right: ($grid-gutter / 2); 32 | padding-left: ($grid-gutter / 2); 33 | float: left; 34 | width: percentage($size / $columns); 35 | } 36 | 37 | 38 | @mixin make-col-offset($size, $columns: $grid-columns) { 39 | margin-left: percentage($size / $columns); 40 | } 41 | 42 | @mixin make-col-push($size, $columns: $grid-columns) { 43 | left: if($size > 0, percentage($size / $columns), auto); 44 | } 45 | 46 | @mixin make-col-pull($size, $columns: $grid-columns) { 47 | right: if($size > 0, percentage($size / $columns), auto); 48 | } 49 | 50 | @mixin make-col-modifier($type, $size, $columns) { 51 | // Work around the lack of dynamic mixin @include support (https://github.com/sass/sass/issues/626) 52 | @if $type == push { 53 | @include make-col-push($size, $columns); 54 | } @else if $type == pull { 55 | @include make-col-pull($size, $columns); 56 | } @else if $type == offset { 57 | @include make-col-offset($size, $columns); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /public/bower_components/basecoat/scss/primer-marketing.scss: -------------------------------------------------------------------------------- 1 | // 2 | // All the Basecoats 3 | // 4 | 5 | // Basecoat requirements 6 | @import "variables-marketing"; 7 | 8 | // Basecoat Basecoat 9 | @import "layout"; 10 | @import "type"; 11 | @import "utility"; 12 | -------------------------------------------------------------------------------- /public/bower_components/primer-css/scss/_base.scss: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | } 4 | 5 | input, 6 | select, 7 | textarea, 8 | button { 9 | font: #{$body-font-size}/1.4 $body-font; 10 | } 11 | 12 | body { 13 | font: #{$body-font-size}/1.4 $body-font; 14 | color: $text-gray-dark; 15 | background-color: $bg-white; 16 | } 17 | 18 | a { 19 | color: $text-blue; 20 | text-decoration: none; 21 | 22 | &:hover, 23 | &:active { 24 | text-decoration: underline; 25 | } 26 | } 27 | 28 | // Horizontal lines 29 | // 30 | // TODO-MDO: Remove `.rule` from everywhere and replace with `
`s 31 | hr, 32 | .rule { 33 | height: 0; 34 | margin: 15px 0; 35 | overflow: hidden; 36 | background: transparent; 37 | border: 0; 38 | border-bottom: 1px solid #ddd; 39 | @include clearfix(); 40 | } 41 | -------------------------------------------------------------------------------- /public/bower_components/primer-css/scss/_button-group.scss: -------------------------------------------------------------------------------- 1 | // Button group 2 | // 3 | // A button group is a series of buttons laid out next to each other, all part 4 | // of one visual button, but separated by rules to be separate. 5 | // scss-lint:disable NestingDepth 6 | .btn-group { 7 | display: inline-block; 8 | vertical-align: middle; 9 | @include clearfix(); 10 | 11 | .btn { 12 | position: relative; 13 | float: left; 14 | 15 | &:not(:first-child):not(:last-child) { 16 | border-radius: 0; 17 | } 18 | 19 | &:first-child:not(:last-child) { 20 | border-top-right-radius: 0; 21 | border-bottom-right-radius: 0; 22 | } 23 | 24 | &:last-child:not(:first-child) { 25 | border-top-left-radius: 0; 26 | border-bottom-left-radius: 0; 27 | } 28 | 29 | // Bring any button into forefront for proper borders given negative margin below 30 | &:hover, 31 | &:active, 32 | &.selected { 33 | z-index: 2; 34 | } 35 | 36 | &:focus { 37 | z-index: 3; 38 | } 39 | 40 | // Tuck buttons into one another to prevent double border 41 | + .btn { 42 | margin-left: -1px; 43 | } 44 | } 45 | 46 | .btn + .btn-group-form, 47 | .btn-group-form + .btn, 48 | .btn-group-form + .btn-group-form { 49 | margin-left: -1px; 50 | } 51 | 52 | .btn-group-form { 53 | float: left; 54 | 55 | .btn { 56 | border-radius: 0; 57 | } 58 | 59 | &:first-child { 60 | .btn { 61 | border-top-left-radius: 3px; 62 | border-bottom-left-radius: 3px; 63 | } 64 | } 65 | 66 | &:last-child { 67 | .btn { 68 | border-top-right-radius: 3px; 69 | border-bottom-right-radius: 3px; 70 | } 71 | } 72 | } 73 | } 74 | 75 | // Proper spacing for multiple button groups (a la, gollum editor) 76 | .btn-group + .btn-group, 77 | .btn-group + .btn { 78 | margin-left: 5px; 79 | } 80 | -------------------------------------------------------------------------------- /public/bower_components/primer-css/scss/_filter-list.scss: -------------------------------------------------------------------------------- 1 | // Filters list 2 | // 3 | // A vertical list of filters. 4 | .filter-list { 5 | list-style-type: none; 6 | 7 | &.small .filter-item { 8 | padding: 4px 10px; 9 | margin: 0 0 2px; 10 | font-size: 12px; 11 | } 12 | 13 | &.pjax-active .filter-item { 14 | color: $text-gray; 15 | background-color: transparent; 16 | 17 | &.pjax-active { 18 | color: $text-white; 19 | background-color: $bg-blue; 20 | } 21 | } 22 | } 23 | 24 | .filter-item { 25 | position: relative; 26 | display: block; 27 | padding: 8px 10px; 28 | margin-bottom: 5px; 29 | overflow: hidden; 30 | font-size: 14px; 31 | color: $text-gray; 32 | text-decoration: none; 33 | text-overflow: ellipsis; 34 | white-space: nowrap; 35 | cursor: pointer; 36 | border-radius: 3px; 37 | 38 | &:hover { 39 | text-decoration: none; 40 | background-color: #eee; 41 | } 42 | 43 | &.selected { 44 | color: $text-white; 45 | background-color: $bg-blue; 46 | 47 | .octicon-remove-close { 48 | float: right; 49 | opacity: 0.8; 50 | } 51 | } 52 | 53 | .count { 54 | float: right; 55 | font-weight: bold; 56 | } 57 | 58 | .bar { 59 | position: absolute; 60 | top: 2px; 61 | right: 0; 62 | bottom: 2px; 63 | z-index: -1; 64 | display: inline-block; 65 | background-color: #f1f1f1; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /public/bower_components/primer-css/scss/_form-select.scss: -------------------------------------------------------------------------------- 1 | // Custom select 2 | // 3 | // Apply `.select` to any `