From 7e779dbebc234c96e2230de63af0c1ccff6a2a73 Mon Sep 17 00:00:00 2001 From: singhmahipal Date: Wed, 10 Dec 2025 19:35:58 +0530 Subject: [PATCH] Show Upload File button when unauthenticated and prompt login (#3079) --- .babelrc | 14 +- .eslintrc | 76 +- .github/CODE_OF_CONDUCT.md | 54 +- .github/CONTRIBUTING.md | 63 +- .github/ISSUE_TEMPLATE/config.yml | 2 +- .../existing-feature-enhancement.yml | 2 +- .github/ISSUE_TEMPLATE/feature-request.yml | 2 +- .github/ISSUE_TEMPLATE/found-a-bug.yml | 30 +- .github/PULL_REQUEST_TEMPLATE.md | 10 +- .github/config.yml | 2 + .github/workflows/deploy-staging.yml | 6 +- .github/workflows/deploy.yml | 7 +- .prettierrc | 4 +- .storybook/preview-head.html | 8 +- .travis.yml | 8 +- client/common/Button.stories.jsx | 2 +- client/common/icons.tsx | 8 +- client/components/Menubar/MenubarItem.tsx | 7 +- client/components/Menubar/MenubarSubmenu.tsx | 16 +- client/components/Menubar/contexts.tsx | 8 +- .../modules/IDE/actions/preferences.types.ts | 3 +- .../CollectionList/CollectionList.jsx | 6 +- .../CollectionList/CollectionListRow.jsx | 558 +- client/modules/IDE/components/Console.jsx | 8 +- client/modules/IDE/components/ErrorModal.jsx | 4 +- client/modules/IDE/components/FileNode.jsx | 179 +- client/modules/IDE/components/Header/Nav.jsx | 8 +- client/modules/IDE/components/Sidebar.jsx | 56 +- .../IDE/reducers/editorAccessibility.js | 7 +- client/modules/Preview/EmbedFrame.jsx | 7 +- client/routes.jsx | 9 +- client/styles/abstracts/_functions.scss | 11 +- client/styles/abstracts/_mixins.scss | 30 +- client/styles/abstracts/_placeholders.scss | 427 +- client/styles/abstracts/_variables.scss | 91 +- client/styles/base/_base.scss | 160 +- client/styles/base/_reset.scss | 25 +- client/styles/components/_account.scss | 6 +- client/styles/components/_api-key.scss | 42 +- client/styles/components/_asset-list.scss | 10 +- client/styles/components/_asset-size.scss | 2 +- client/styles/components/_banner.scss | 8 +- .../styles/components/_collection-create.scss | 2 +- client/styles/components/_collection.scss | 23 +- client/styles/components/_console-input.scss | 18 +- client/styles/components/_console.scss | 184 +- client/styles/components/_copyable-input.scss | 9 +- .../styles/components/_dashboard-header.scss | 19 +- client/styles/components/_editable-input.scss | 4 +- client/styles/components/_editor.scss | 69 +- client/styles/components/_error-modal.scss | 2 +- client/styles/components/_feedback.scss | 4 +- client/styles/components/_form-container.scss | 88 +- client/styles/components/_forms.scss | 23 +- client/styles/components/_hints.scss | 69 +- .../components/_keyboard-shortcuts.scss | 6 +- client/styles/components/_modal.scss | 11 +- client/styles/components/_nav.scss | 37 +- client/styles/components/_new-password.scss | 2 +- client/styles/components/_overlay.scss | 4 +- .../_p5-contrast-codemirror-theme.scss | 42 +- .../components/_p5-dark-codemirror-theme.scss | 38 +- .../_p5-light-codemirror-theme.scss | 31 +- client/styles/components/_preferences.scss | 39 +- client/styles/components/_preview-frame.scss | 2 +- client/styles/components/_preview-nav.scss | 4 +- client/styles/components/_quick-add.scss | 18 +- client/styles/components/_reset-password.scss | 2 +- client/styles/components/_resizer.scss | 60 +- client/styles/components/_searchbar.scss | 5 +- client/styles/components/_share.scss | 4 +- client/styles/components/_sidebar.scss | 148 +- client/styles/components/_sketch-list.scss | 49 +- client/styles/components/_skip-link.scss | 5 +- client/styles/components/_tabs.scss | 23 +- client/styles/components/_timer.scss | 2 +- client/styles/components/_toast.scss | 6 +- client/styles/components/_toggle.scss | 74 +- client/styles/components/_toolbar.scss | 292 +- .../components/_visibility-dropdown.scss | 42 +- client/styles/layout/_dashboard.scss | 2 +- client/styles/layout/_ide.scss | 4 +- client/styles/main.scss | 2 +- client/tsconfig.json | 4 +- client/utils/codemirror-search.js | 20 +- client/utils/dispatcher.test.ts | 6 +- client/utils/evaluateExpression.ts | 44 +- client/utils/htmlmixed.js | 265 +- .../p5-instance-methods-and-creators.json | 163 +- client/utils/p5-javascript.js | 2262 ++--- client/utils/p5-keywords.js | 498 +- client/utils/p5-reference-functions.json | 754 +- .../utils/p5-scope-function-access-map.json | 64 +- client/utils/reduxFormUtils.ts | 20 +- .../GSOC_hinter_and_refactoring_changes.md | 18 +- contributor_docs/accessibility.md | 71 +- contributor_docs/deployment.md | 19 +- contributor_docs/development.md | 77 +- contributor_docs/installation.md | 39 +- contributor_docs/preparing_a_pull_request.md | 26 +- contributor_docs/preparing_an_issue.md | 32 +- contributor_docs/public_api.md | 49 +- contributor_docs/public_api_proposed.md | 61 +- contributor_docs/release.md | 15 +- contributor_docs/s3_configuration.md | 15 +- contributor_docs/testing.md | 236 +- contributor_docs/translations.md | 65 +- docker-compose.yml | 61 +- infrastructure/README.md | 12 +- .../terraform/.terraform/terraform.tfstate | 2 +- infrastructure/terraform/README.md | 14 + kubernetes_app.yml | 124 +- nodemon.json | 12 +- package-lock.json | 7342 +++-------------- public/code-of-conduct.md | 54 +- public/privacy-policy.md | 179 +- public/terms-of-use.md | 158 +- server/controllers/embed.controller.js | 5 +- .../user.controller/__testUtils__.ts | 2 +- .../user.controller/__tests__/apiKey.test.ts | 32 +- .../authManagement/3rdPartyManagement.test.ts | 16 +- .../authManagement/passwordManagement.test.ts | 44 +- .../authManagement/updateSettings.test.ts | 64 +- .../user.controller/__tests__/helpers.test.ts | 18 +- .../user.controller/__tests__/signup.test.ts | 48 +- .../__tests__/userPreferences.test.ts | 24 +- .../__tests__/isAuthenticated.test.ts | 6 +- server/migrations/emailConsolidation.js | 117 - server/migrations/truncate.js | 41 +- server/models/project.js | 19 +- server/models/user.ts | 29 +- server/routes/passport.routes.ts | 51 +- server/scripts/examples.js | 6 +- server/utils/fileUtils.js | 9 +- server/views/404Page.js | 5 +- .../contributor_docs/ko/CONTRIBUTING.md | 91 +- translations/contributor_docs/ko/README.md | 12 +- .../contributor_docs/ko/installation.md | 16 +- translations/contributor_docs/pt-br/README.md | 20 +- .../contributor_docs/pt-br/accessibility.md | 14 +- .../contributor_docs/pt-br/deployment.md | 25 +- .../contributor_docs/pt-br/development.md | 21 +- .../contributor_docs/pt-br/installation.md | 16 +- .../pt-br/preparing_a_pull_request.md | 18 +- .../contributor_docs/pt-br/public_api.md | 44 +- .../pt-br/public_api_proposed.md | 56 +- translations/locales/de/translations.json | 9 +- translations/locales/en-US/translations.json | 9 +- translations/locales/es-419/translations.json | 10 +- translations/locales/fr-CA/translations.json | 1221 ++- translations/locales/it/translations.json | 10 +- translations/locales/ja/translations.json | 1204 +-- translations/locales/ko/translations.json | 12 +- translations/locales/sv/translations.json | 11 +- translations/locales/tr/translations.json | 4 +- translations/locales/uk-UA/translations.json | 42 +- translations/locales/ur/translations.json | 1221 ++- translations/locales/zh-CN/translations.json | 12 +- translations/locales/zh-TW/translations.json | 10 +- tsconfig.base.json | 2 +- tsconfig.json | 7 +- 161 files changed, 8405 insertions(+), 12483 deletions(-) diff --git a/.babelrc b/.babelrc index 3bb00f57cf..3110a00bc4 100644 --- a/.babelrc +++ b/.babelrc @@ -44,16 +44,10 @@ "@babel/plugin-proposal-function-bind", ["@babel/plugin-proposal-private-methods", { "loose": true }] ], - "presets": [ - "@babel/preset-env", - "@babel/preset-react" - ] + "presets": ["@babel/preset-env", "@babel/preset-react"] }, "development": { - "plugins": [ - "babel-plugin-styled-components", - "react-refresh/babel" - ], + "plugins": ["babel-plugin-styled-components", "react-refresh/babel"], "presets": [ [ "@babel/preset-react", @@ -74,9 +68,7 @@ } ] ], - "plugins": [ - "babel-plugin-styled-components" - ] + "plugins": ["babel-plugin-styled-components"] } }, "plugins": [ diff --git a/.eslintrc b/.eslintrc index 22dddfeffb..396f313df1 100644 --- a/.eslintrc +++ b/.eslintrc @@ -1,7 +1,7 @@ { - "extends": ["airbnb", "prettier", "plugin:storybook/recommended"], - "parser": "@babel/eslint-parser", - "env": { + "extends": ["airbnb", "prettier", "plugin:storybook/recommended"], + "parser": "@babel/eslint-parser", + "env": { "browser": true, "node": true, "jest": true @@ -17,9 +17,10 @@ "import/no-named-as-default": 0, "import/no-named-as-default-member": 0, "import/no-useless-path-segments": 1, - "import/no-cycle":0, //temporarily off + "import/no-cycle": 0, //temporarily off "import/no-import-module-exports": 0, //temporarily off - "import/extensions": [ // override airbnb setting to allow imports of js, jsx, ts, and tsx files to auto-resolve instead of error + "import/extensions": [ + // override airbnb setting to allow imports of js, jsx, ts, and tsx files to auto-resolve instead of error "error", "ignorePackages", { @@ -31,9 +32,9 @@ ], "import/prefer-default-export": "off", "react/jsx-filename-extension": [1, { "extensions": [".jsx", ".tsx"] }], - "comma-dangle": 0, // not sure why airbnb turned this on. gross! + "comma-dangle": 0, // not sure why airbnb turned this on. gross! "default-param-last": 0, - "no-else-return" :0, + "no-else-return": 0, "indent": 0, "no-console": 0, "no-alert": 0, @@ -44,31 +45,40 @@ "no-useless-catch": 2, "no-plusplus": "off", "prefer-object-spread": 0, - "max-len": [1, 120, 2, {"ignoreComments": true, "ignoreTemplateLiterals": true}], + "max-len": [ + 1, + 120, + 2, + { "ignoreComments": true, "ignoreTemplateLiterals": true } + ], "max-classes-per-file": 0, "quote-props": [1, "as-needed"], - "no-unused-vars": [1, {"vars": "local", "args": "none"}], + "no-unused-vars": [1, { "vars": "local", "args": "none" }], "consistent-return": ["error", { "treatUndefinedAsUnspecified": true }], "no-param-reassign": [2, { "props": false }], - "react/self-closing-comp": ["error", { - "component": true, - "html": false - }], + "react/self-closing-comp": [ + "error", + { + "component": true, + "html": false + } + ], "newline-per-chained-call": 0, - "react/prefer-stateless-function": [2, - { "ignorePureComponents": true - }], + "react/prefer-stateless-function": [2, { "ignorePureComponents": true }], "class-methods-use-this": 0, "react/button-has-type": 0, - "react/destructuring-assignment":0, + "react/destructuring-assignment": 0, "react/function-component-definition": 0, - "react/jsx-curly-newline":0, - "react/jsx-fragments":0, - "react/jsx-no-useless-fragment":0, // temporarily off + "react/jsx-curly-newline": 0, + "react/jsx-fragments": 0, + "react/jsx-no-useless-fragment": 0, // temporarily off "react/jsx-one-expression-per-line": 0, "react/jsx-props-no-spreading": 0, "react/jsx-wrap-multilines": 0, - "react/jsx-no-bind": [2, {"allowBind": true, "allowArrowFunctions": true, "allowFunctions": true}], + "react/jsx-no-bind": [ + 2, + { "allowBind": true, "allowArrowFunctions": true, "allowFunctions": true } + ], "react/no-deprecated": 0, //temporarily off "react/no-unused-class-component-methods": 1, "react/sort-comp": 0, @@ -76,12 +86,8 @@ "jsx-a11y/anchor-is-valid": [ "error", { - "components": [ - "Link" - ], - "specialLink": [ - "to" - ] + "components": ["Link"], + "specialLink": ["to"] } ], "jsx-a11y/control-has-associated-label": 0, //temporarily off @@ -89,24 +95,16 @@ "jsx-a11y/label-has-for": [ 2, { - "components": [ - "Label" - ], + "components": ["Label"], "required": { - "every": [ - "id" - ] + "every": ["id"] }, "allowChildren": false } ], - "prettier/prettier": [ - "error" - ] + "prettier/prettier": ["warn"] }, - "plugins": [ - "react", "jsx-a11y", "import", "prettier" - ], + "plugins": ["react", "jsx-a11y", "import", "prettier"], "settings": { "import/parser": "@babel/eslint-parser", "import/resolver": { diff --git a/.github/CODE_OF_CONDUCT.md b/.github/CODE_OF_CONDUCT.md index b461c37ca9..a9a3f28092 100644 --- a/.github/CODE_OF_CONDUCT.md +++ b/.github/CODE_OF_CONDUCT.md @@ -7,45 +7,49 @@ We are a community of, and in solidarity with, people from every gender identity We like these hashtags: #noCodeSnobs (because we value community over efficiency), #newKidLove (because we all started somewhere), #unassumeCore (because we don't assume knowledge), and #BlackLivesMatter (because of course). In practice: -* We are not code snobs. We do not assume knowledge or imply there are things that somebody should know. -* We insist on actively engaging with requests for feedback regardless of their complexity. -* We welcome newcomers and prioritize the education of others. We strive to approach all tasks with the enthusiasm of a newcomer. Because we believe that newcomers are just as valuable in this effort as experts. -* We consistently make the effort to actively recognize and validate multiple types of contributions. -* We are always willing to offer help or guidance. + +- We are not code snobs. We do not assume knowledge or imply there are things that somebody should know. +- We insist on actively engaging with requests for feedback regardless of their complexity. +- We welcome newcomers and prioritize the education of others. We strive to approach all tasks with the enthusiasm of a newcomer. Because we believe that newcomers are just as valuable in this effort as experts. +- We consistently make the effort to actively recognize and validate multiple types of contributions. +- We are always willing to offer help or guidance. In times of conflict: -* We listen. -* We clearly communicate while acknowledging other's feelings. -* We admit when we're wrong, apologize, and accept responsibility for our actions. -* We are continuously seeking to improve ourselves and our community. -* We keep our community respectful and open. -* We make everyone feel heard. -* We are mindful and kind in our interactions. + +- We listen. +- We clearly communicate while acknowledging other's feelings. +- We admit when we're wrong, apologize, and accept responsibility for our actions. +- We are continuously seeking to improve ourselves and our community. +- We keep our community respectful and open. +- We make everyone feel heard. +- We are mindful and kind in our interactions. In the future: -* The future is now. +- The future is now. ## p5.js Code of Conduct -* **Be mindful of your language.** Any of the following behavior is unacceptable: - * Offensive comments related to gender identity and expression, sexual orientation, race, ethnicity, language, neuro-type, size, ability, class, religion, culture, subculture, political opinion, age, skill level, occupation, or background - * Threats of violence - * Deliberate intimidation - * Sexually explicit or violent material that is not contextualized and preceded by a considerate warning - * Unwelcome sexual attention - * Stalking or following - * Or any other kinds of harassment +- **Be mindful of your language.** Any of the following behavior is unacceptable: + + - Offensive comments related to gender identity and expression, sexual orientation, race, ethnicity, language, neuro-type, size, ability, class, religion, culture, subculture, political opinion, age, skill level, occupation, or background + - Threats of violence + - Deliberate intimidation + - Sexually explicit or violent material that is not contextualized and preceded by a considerate warning + - Unwelcome sexual attention + - Stalking or following + - Or any other kinds of harassment Use your best judgement. If it will possibly make others uncomfortable, do not post it. -* **Be respectful.** Disagreement is not an opportunity to attack someone else's thoughts or opinions. Although views may differ, remember to approach every situation with patience and care. -* **Be considerate.** Think about how your contribution will affect others in the community. -* **Be open minded.** Embrace new people and new ideas. Our community is continually evolving and we welcome positive change. +- **Be respectful.** Disagreement is not an opportunity to attack someone else's thoughts or opinions. Although views may differ, remember to approach every situation with patience and care. +- **Be considerate.** Think about how your contribution will affect others in the community. +- **Be open minded.** Embrace new people and new ideas. Our community is continually evolving and we welcome positive change. If you believe someone is violating the code of conduct, we ask that you report it by emailing [hello@p5js.org](mailto:hello@p5js.org). Please include your name and a description of the incident, and we will get back to you ASAP. Sometimes, participants violating the Code of Conduct are unaware that their behavior is harmful, and an open conversation clears things up to move forward. However, if a participant continues with the behavior, the p5.js team may take any action they deem appropriate, up to and including expulsion from all p5.js spaces and identification of the participant as a harasser to other p5.js members or the general public. --- -This statement is licensed under a [Creative Commons license](https://creativecommons.org/licenses/by-sa/4.0/). Please feel free to share and remix with attribution. \ No newline at end of file + +This statement is licensed under a [Creative Commons license](https://creativecommons.org/licenses/by-sa/4.0/). Please feel free to share and remix with attribution. diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 01d1f4abad..72dd2a52c8 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -2,63 +2,71 @@ Welcome to the Contributor Guidelines! -This document is for anyone interested in contributing to the p5.js Editor—whether you're new to open source, refreshing your memory on some technical steps, or curious about how the codebase works! +This document is for anyone interested in contributing to the p5.js Editor—whether you're new to open source, refreshing your memory on some technical steps, or curious about how the codebase works! We believe that anyone can be a contributor; you don’t need to be an expert. We also know that not everyone has the same time, energy, or resources to spend, and that’s okay. We’re just glad you’re here! -This guide has been adapted from the Contributor Guidelines within the [Processing](https://github.com/processing/processing4/blob/main/CONTRIBUTING.md) and [p5.js](https://github.com/processing/p5.js/blob/main/contributor_docs/contributor_guidelines.md) repositories. They're full of helpful and in-depth resources—please check them out! +This guide has been adapted from the Contributor Guidelines within the [Processing](https://github.com/processing/processing4/blob/main/CONTRIBUTING.md) and [p5.js](https://github.com/processing/p5.js/blob/main/contributor_docs/contributor_guidelines.md) repositories. They're full of helpful and in-depth resources—please check them out! If you haven't already, read our [Community and Statement Code of Conduct](https://editor.p5js.org/code-of-conduct) to understand the values that guide our community and how to participate respectfully and constructively. ## Table of Contents + - [About Github](#about-github) - [How Can I Contribute?](#how-can-i-contribute) - [Working Within the Codebase](#working-within-the-codebase) - [Ideas for Getting Started](#ideas-for-getting-started) ## About Github + The p5.js Editor’s codebase is hosted on [GitHub](https://github.com/processing). GitHub is a website where people can collaborate on code. It’s widely used for open source projects and makes it easier to keep track of changes, report issues with the software, and contribute improvements to the code. If you're new to GitHub, a good place to start is the [First Contribution's tutorial guide](https://github.com/firstcontributions/first-contributions/blob/main/docs/gui-tool-tutorials/github-desktop-tutorial.md), which walks you through the basics of contributing to a project using GitHub Desktop. For more information, we recommend [Git and GitHub for Poets](https://www.youtube.com/playlist?list=PLRqwX-V7Uu6ZF9C0YMKuns9sLDzK6zoiV), a beginner-friendly video series. -The [Hello World](https://guides.github.com/activities/hello-world/) and [Forking](https://guides.github.com/activities/forking/) Guides from Github are also great acitivities for exercising how you might want to use these tools and features. +The [Hello World](https://guides.github.com/activities/hello-world/) and [Forking](https://guides.github.com/activities/forking/) Guides from Github are also great acitivities for exercising how you might want to use these tools and features. ## How Can I Contribute? -If you're new to open source, start by reading [this beginner-friendly guide about contributing to an open source project](https://opensource.guide/how-to-contribute/). It covers why you might want to contribute to a project, what it means to contribute, and how to navigate certain aspects of the contribution process. + +If you're new to open source, start by reading [this beginner-friendly guide about contributing to an open source project](https://opensource.guide/how-to-contribute/). It covers why you might want to contribute to a project, what it means to contribute, and how to navigate certain aspects of the contribution process. ### First Steps + As you start navigating the p5.js editor and the codebase, you may want to think about what you're hoping to learn by working on open source project. The p5.js editor is a full-stack web application, therefore there's tons of different areas that you could focus on. Some of them can look like: - - - **Translation** – Help localize the software and documentation in your language. Many of us made our first contribution this way. - - **Testing** – Try out new releases and report bugs. - - **Documentation** – Improve tutorials, reference pages, or even this guide! - - **Design** – Contribute UI design ideas or help improve user experience. - - **Project Management** - Organizing tickets, pull requests, and tasks. - - **Front-End Development** - We use React/Redux, CSS/Sass, and CodeMirror. - - **Back-End Development** - We use Node, Express, MongoDB, Jest, and AWS. - - **DevOps** - Some tools we use are Travis CI, Jest, Docker, Kubernetes, and AWS. - - **Community Support** – Answer questions on the forum. - - **Education** – Create learning resources, curriculums, organize workshops, or share your teaching experiences. - - **Art and Projects** – Share what you’re making with p5.js or the p5.js Editor! - - **Outreach and Advocacy** – Help others discover and get excited about the project. + +- **Translation** – Help localize the software and documentation in your language. Many of us made our first contribution this way. +- **Testing** – Try out new releases and report bugs. +- **Documentation** – Improve tutorials, reference pages, or even this guide! +- **Design** – Contribute UI design ideas or help improve user experience. +- **Project Management** - Organizing tickets, pull requests, and tasks. +- **Front-End Development** - We use React/Redux, CSS/Sass, and CodeMirror. +- **Back-End Development** - We use Node, Express, MongoDB, Jest, and AWS. +- **DevOps** - Some tools we use are Travis CI, Jest, Docker, Kubernetes, and AWS. +- **Community Support** – Answer questions on the forum. +- **Education** – Create learning resources, curriculums, organize workshops, or share your teaching experiences. +- **Art and Projects** – Share what you’re making with p5.js or the p5.js Editor! +- **Outreach and Advocacy** – Help others discover and get excited about the project. Once you've found something you're excited to contribute to, reference the relevant guides and documentation to make sure you're following the recommended process. ## Working Within the Codebase ### Making Your First Contribution + Issues with these labels are a great place to start! + - [Help Wanted](https://github.com/processing/p5.js-web-editor/labels/Help%20Wanted) - [Good First Issue](https://github.com/processing/p5.js-web-editor/labels/Good%20First%20Issue) - [Need Steps to Reproduce](https://github.com/processing/p5.js-web-editor/labels/Needs%20Steps%20to%20Reproduce) - [Ready for Work](https://github.com/processing/p5.js-web-editor/labels/Ready%20for%20Work) -A breakdown of what each label means can be found in the [Preparing an Issue Guide](../contributor_docs/preparing_an_issue.md). +A breakdown of what each label means can be found in the [Preparing an Issue Guide](../contributor_docs/preparing_an_issue.md). When approaching these issues, know that it's okay to not know how to fix an issue! Feel free to ask questions about to approach the problem. We are all here to learn and make something awesome. Someone from the community will help you out, and asking questions is a great way to learn about the p5.js editor, its file structure, and development process. ### Before You Start Working On An Issue + Before beginning work on a code contribution, please make sure that: + - The issue has been discussed and a proposed solution has been agreed upon. - You have been assigned to the issue. - If an implementation has been agreed upon but no one has volunteered to take it on, feel free to comment and offer to help. A maintainer can then assign the issue to you. @@ -67,25 +75,26 @@ Before beginning work on a code contribution, please make sure that: The best way to verify if an issue is ready to be worked on is checking if it has the [Ready for Work](https://github.com/processing/p5.js-web-editor/labels/Ready%20for%20Work) label. However, here are a few other suggestions to keep in mind as you explore the issues: -- **Please do not open a pull request for an issue that is already assigned to someone else**. We follow a “first assigned, first served” approach to avoid duplicated work. If you open a PR for an issue that someone else is already working on, your PR will be closed. +- **Please do not open a pull request for an issue that is already assigned to someone else**. We follow a “first assigned, first served” approach to avoid duplicated work. If you open a PR for an issue that someone else is already working on, your PR will be closed. - If an issue has been inactive for a long time, you’re welcome to check in politely by commenting to see if the assignee still plans to work on it or would be open to someone else taking over. - There’s no hard deadline for completing contributions. We understand that people often contribute on a volunteer basis and timelines may vary. That said, if you run into trouble or have questions at any point, don’t hesitate to ask for help in the issue thread. Maintainers and other community members are here to support you. ### Before Submitting a Pull Request -Before submitting a pull request, make sure that: -- Your work is related to an issue. **Pull requests that do not have an associated issue will not be accepted.** -- Your work adheres to the style guidelines and fits in with the rest of the codebase. + +Before submitting a pull request, make sure that: + +- Your work is related to an issue. **Pull requests that do not have an associated issue will not be accepted.** +- Your work adheres to the style guidelines and fits in with the rest of the codebase. - You ran the project locally and tested your changes. Pay special attention to any specific areas of the p5.js editor that may be affected by your changes. Does everything still work as before? Great! - You reference the [Preparing a Pull Request Guide](https://github.com/processing/p5.js-web-editor/blob/develop/contributor_docs/preparing_a_pull_request.md) for more details! --- ## Ideas for Getting Started -* Use the [p5.js Editor](https://editor.p5js.org)! Find a bug? Think of something you think would add to the project? Reference the [Preparing an Issue Guide](../contributor_docs/preparing_an_issue.md) and open an issue. -* Expand an existing issue. Sometimes issues are missing steps to reproduce, or need suggestions for potential solutions. Sometimes they need another voice saying, "this is really important!" -* Try getting the project running locally on your computer by following the [installation steps](./../contributor_docs/installation.md). -* Look through the documentation in the [developer docs](../contributor_docs/) and the [development guide](./../contributor_docs/development.md). Is there anything that could be expanded? Is there anything missing? - +- Use the [p5.js Editor](https://editor.p5js.org)! Find a bug? Think of something you think would add to the project? Reference the [Preparing an Issue Guide](../contributor_docs/preparing_an_issue.md) and open an issue. +- Expand an existing issue. Sometimes issues are missing steps to reproduce, or need suggestions for potential solutions. Sometimes they need another voice saying, "this is really important!" +- Try getting the project running locally on your computer by following the [installation steps](./../contributor_docs/installation.md). +- Look through the documentation in the [developer docs](../contributor_docs/) and the [development guide](./../contributor_docs/development.md). Is there anything that could be expanded? Is there anything missing? diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 989b925781..31f233c5df 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -9,4 +9,4 @@ contact_links: about: Report issues with the p5.js website here. - name: 💬 Forum url: https://discourse.processing.org/c/p5js - about: Have other questions about using p5.js? Ask them here! \ No newline at end of file + about: Have other questions about using p5.js? Ask them here! diff --git a/.github/ISSUE_TEMPLATE/existing-feature-enhancement.yml b/.github/ISSUE_TEMPLATE/existing-feature-enhancement.yml index 515465b661..8027236256 100644 --- a/.github/ISSUE_TEMPLATE/existing-feature-enhancement.yml +++ b/.github/ISSUE_TEMPLATE/existing-feature-enhancement.yml @@ -1,6 +1,6 @@ name: 💡 Existing Feature Enhancement description: Suggest an improvement to an existing feature. -labels: [ Enhancement, Awaiting Maintainer Approval ] +labels: [Enhancement, Awaiting Maintainer Approval] body: - type: textarea attributes: diff --git a/.github/ISSUE_TEMPLATE/feature-request.yml b/.github/ISSUE_TEMPLATE/feature-request.yml index 0976af9cb0..c1a669edfd 100644 --- a/.github/ISSUE_TEMPLATE/feature-request.yml +++ b/.github/ISSUE_TEMPLATE/feature-request.yml @@ -1,6 +1,6 @@ name: 🌱 New Feature Request description: Request a new feature be added. -labels: [ Feature Request, Awaiting Maintainer Approval ] +labels: [Feature Request, Awaiting Maintainer Approval] body: - type: textarea attributes: diff --git a/.github/ISSUE_TEMPLATE/found-a-bug.yml b/.github/ISSUE_TEMPLATE/found-a-bug.yml index 1855943525..1bf0a76a68 100644 --- a/.github/ISSUE_TEMPLATE/found-a-bug.yml +++ b/.github/ISSUE_TEMPLATE/found-a-bug.yml @@ -1,6 +1,6 @@ name: 🐛 Found a Bug description: Report p5.js web editor bugs (broken or incorrect behaviour). -labels: [ Bug, Awaiting Maintainer Approval ] +labels: [Bug, Awaiting Maintainer Approval] body: - type: markdown attributes: @@ -57,20 +57,18 @@ body: description: | - Add steps to reproduce bugs or add information on the place where the feature should be implemented. - Add links to a sample deployment or code. - value: "### Steps: - - 1. - 2. - 3. - - ### Snippet: - - ```js - - - // Paste your code here :) - - - ```" + value: '### Steps: + + 1. 2. 3. + + ### Snippet: + + ```js + + + // Paste your code here :) + + + ```' validations: required: true diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index df080857be..c76f1e6f24 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -4,8 +4,8 @@ Changes: I have verified that this pull request: -* [ ] has no linting errors (`npm run lint`) -* [ ] has no test errors (`npm run test`) -* [ ] is from a uniquely-named feature branch and is up to date with the `develop` branch. -* [ ] is descriptively named and links to an issue number, i.e. `Fixes #123` -* [ ] meets the standards outlined in the [accessibility guidelines](https://github.com/processing/p5.js-web-editor/blob/develop/contributor_docs/accessibility.md) +- [ ] has no linting errors (`npm run lint`) +- [ ] has no test errors (`npm run test`) +- [ ] is from a uniquely-named feature branch and is up to date with the `develop` branch. +- [ ] is descriptively named and links to an issue number, i.e. `Fixes #123` +- [ ] meets the standards outlined in the [accessibility guidelines](https://github.com/processing/p5.js-web-editor/blob/develop/contributor_docs/accessibility.md) diff --git a/.github/config.yml b/.github/config.yml index c104c86c8e..24d52c224a 100644 --- a/.github/config.yml +++ b/.github/config.yml @@ -6,12 +6,14 @@ newIssueWelcomeComment: > Welcome! 👋 Thanks for opening your first issue here! And to ensure the community is able to respond to your issue, be sure to follow the issue template if you haven't already. + # Configuration for new-pr-welcome - https://github.com/behaviorbot/new-pr-welcome # Comment to be posted to on PRs from first time contributors in your repository newPRWelcomeComment: > 🎉 Thanks for opening this pull request! Please check out our [contributing guidelines](https://github.com/processing/p5.js-web-editor/blob/develop/.github/CONTRIBUTING.md) if you haven't already. + # Configuration for first-pr-merge - https://github.com/behaviorbot/first-pr-merge # Comment to be posted to on pull requests merged by a first time user diff --git a/.github/workflows/deploy-staging.yml b/.github/workflows/deploy-staging.yml index e708b71558..a35eba0f3c 100644 --- a/.github/workflows/deploy-staging.yml +++ b/.github/workflows/deploy-staging.yml @@ -1,7 +1,7 @@ name: Deploy to staging on: workflow_run: - workflows: ["Test"] + workflows: ['Test'] branches: - develop types: @@ -43,11 +43,11 @@ jobs: with: service_account_key: ${{ secrets.GKE_SA_KEY }} project_id: ${{ secrets.GKE_PROJECT }} - + # Configure docker to use the gcloud command-line tool as a credential helper - run: |- gcloud --quiet auth configure-docker - + # Get the GKE credentials so we can deploy to the cluster - uses: google-github-actions/get-gke-credentials@v0.2.1 with: diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 08e8f4ffe5..4592b23d07 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -1,7 +1,7 @@ name: Deploy to production on: workflow_run: - workflows: ["Test"] + workflows: ['Test'] branches: - release types: @@ -47,11 +47,11 @@ jobs: with: service_account_key: ${{ secrets.GKE_SA_KEY }} project_id: ${{ secrets.GKE_PROJECT }} - + # Configure docker to use the gcloud command-line tool as a credential helper - run: |- gcloud --quiet auth configure-docker - + # Get the GKE credentials so we can deploy to the cluster - uses: google-github-actions/get-gke-credentials@v0.2.1 with: @@ -64,4 +64,3 @@ jobs: run: |- kubectl set image deployment/$DEPLOYMENT_NAME web-editor-app=index.docker.io/$IMAGE:$GITHUB_SHA --namespace=production kubectl get services -o wide - diff --git a/.prettierrc b/.prettierrc index df6b0841b0..87446977ec 100644 --- a/.prettierrc +++ b/.prettierrc @@ -14,5 +14,5 @@ "trailingComma": "none", "useTabs": false, "quoteProps": "as-needed", - "endOfLine":"auto" -} \ No newline at end of file + "endOfLine": "auto" +} diff --git a/.storybook/preview-head.html b/.storybook/preview-head.html index cd078bfceb..daaeebfcf8 100644 --- a/.storybook/preview-head.html +++ b/.storybook/preview-head.html @@ -1,5 +1,5 @@ \ No newline at end of file + // https://github.com/pmmmwh/react-refresh-webpack-plugin/issues/176#issuecomment-683150213 + window.$RefreshReg$ = () => {}; + window.$RefreshSig$ = () => () => {}; + diff --git a/.travis.yml b/.travis.yml index 553859080c..213da6c72c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,11 +1,11 @@ sudo: required language: node_js node_js: - - "18.20.8" + - '18.20.8' cache: directories: - - "$HOME/google-cloud-sdk/" + - '$HOME/google-cloud-sdk/' services: - docker @@ -19,10 +19,10 @@ install: true jobs: include: - stage: test - name: "Linting" + name: 'Linting' script: docker-compose exec -T app npm run lint - # stage name not required, will continue to use `test` - name: "Tests" + name: 'Tests' script: docker-compose exec -T app npm run test before_deploy: diff --git a/client/common/Button.stories.jsx b/client/common/Button.stories.jsx index 0a0150a5b6..6e5c8eecf3 100644 --- a/client/common/Button.stories.jsx +++ b/client/common/Button.stories.jsx @@ -1,7 +1,7 @@ import React from 'react'; import { action } from '@storybook/addon-actions'; -import { Button, ButtonDisplays, ButtonKinds, ButtonTypes } from './Button'; +import { Button, ButtonDisplays, ButtonTypes } from './Button'; import { GithubIcon, DropdownArrowIcon, PlusIcon } from './icons'; export default { diff --git a/client/common/icons.tsx b/client/common/icons.tsx index 80411bf937..1ba4df4a36 100644 --- a/client/common/icons.tsx +++ b/client/common/icons.tsx @@ -25,6 +25,7 @@ import Add from '../images/add.svg'; import Filter from '../images/filter.svg'; import Cross from '../images/cross.svg'; import Copy from '../images/copy.svg'; +import Lock from '../images/lock.svg'; export interface IconColors { default?: string; @@ -36,11 +37,6 @@ export interface IconProps extends React.SVGProps { Icon?: IconColors; } -// HOC that adds the right web accessibility props -// https://www.scottohara.me/blog/2019/05/22/contextual-images-svgs-and-a11y.html - -// could also give these a default size, color, etc. based on the theme -// Need to add size to these - like small icon, medium icon, large icon. etc. function withLabel( SvgComponent: React.ComponentType> ) { @@ -65,7 +61,6 @@ function withLabel( } `; - // Necessary because styled components inject a different type for the ref prop type StyledIconProps = Omit< React.ComponentProps, 'ref' @@ -115,3 +110,4 @@ export const CircleInfoIcon = withLabel(CircleInfo); export const AddIcon = withLabel(Add); export const FilterIcon = withLabel(Filter); export const CopyIcon = withLabel(Copy); +export const LockIcon = withLabel(Lock); diff --git a/client/components/Menubar/MenubarItem.tsx b/client/components/Menubar/MenubarItem.tsx index d2b3a1b1a3..506e910a1b 100644 --- a/client/components/Menubar/MenubarItem.tsx +++ b/client/components/Menubar/MenubarItem.tsx @@ -57,11 +57,8 @@ export function MenubarItem({ ...rest }: MenubarItemProps) { const { createMenuItemHandlers, hasFocus } = useContext(MenubarContext); - const { - setSubmenuActiveIndex, - submenuItems, - registerSubmenuItem - } = useContext(SubmenuContext); + const { setSubmenuActiveIndex, submenuItems, registerSubmenuItem } = + useContext(SubmenuContext); const parent = useContext(ParentMenuContext); const menuItemRef = useRef(null); diff --git a/client/components/Menubar/MenubarSubmenu.tsx b/client/components/Menubar/MenubarSubmenu.tsx index d9c3702a5f..b1374311cc 100644 --- a/client/components/Menubar/MenubarSubmenu.tsx +++ b/client/components/Menubar/MenubarSubmenu.tsx @@ -40,10 +40,10 @@ export function useMenuProps(id: string) { const { createMenuHandlers } = useContext(MenubarContext); - const handlers = useMemo(() => createMenuHandlers(id), [ - createMenuHandlers, - id - ]); + const handlers = useMemo( + () => createMenuHandlers(id), + [createMenuHandlers, id] + ); return { isOpen, handlers }; } @@ -98,12 +98,8 @@ const MenubarTrigger = React.forwardRef( }, ref ) => { - const { - setActiveIndex, - menuItems, - registerTopLevelItem, - hasFocus - } = useContext(MenubarContext); + const { setActiveIndex, menuItems, registerTopLevelItem, hasFocus } = + useContext(MenubarContext); const { id, title, first, last } = useContext(SubmenuContext); const { isOpen, handlers } = useMenuProps(id); diff --git a/client/components/Menubar/contexts.tsx b/client/components/Menubar/contexts.tsx index 7580b257a4..5b789171b0 100644 --- a/client/components/Menubar/contexts.tsx +++ b/client/components/Menubar/contexts.tsx @@ -5,17 +5,13 @@ export const ParentMenuContext = createContext('none'); export const MenuOpenContext = createContext('none'); interface MenubarContextType { - createMenuHandlers: ( - id: string - ) => Partial<{ + createMenuHandlers: (id: string) => Partial<{ onMouseOver: (e: React.MouseEvent) => void; onClick: (e: React.MouseEvent) => void; onBlur: (e: React.FocusEvent) => void; onFocus: (e: React.FocusEvent) => void; }>; - createMenuItemHandlers: ( - id: string - ) => Partial<{ + createMenuItemHandlers: (id: string) => Partial<{ onMouseUp: (e: React.MouseEvent) => void; onBlur: (e: React.FocusEvent) => void; onFocus: (e: React.FocusEvent) => void; diff --git a/client/modules/IDE/actions/preferences.types.ts b/client/modules/IDE/actions/preferences.types.ts index e54d28d3cd..4ef954ae2a 100644 --- a/client/modules/IDE/actions/preferences.types.ts +++ b/client/modules/IDE/actions/preferences.types.ts @@ -6,7 +6,8 @@ import type { RootState } from '../../../reducers'; export type SetPreferencesTabValue = PreferencesState['tabIndex']; export type SetFontSizeValue = PreferencesState['fontSize']; export type SetLineNumbersValue = PreferencesState['lineNumbers']; -export type SetAutocloseBracketsQuotesValue = PreferencesState['autocloseBracketsQuotes']; +export type SetAutocloseBracketsQuotesValue = + PreferencesState['autocloseBracketsQuotes']; export type SetAutocompleteHinterValue = PreferencesState['autocompleteHinter']; export type SetAutosaveValue = PreferencesState['autosave']; export type SetLinewrapValue = PreferencesState['linewrap']; diff --git a/client/modules/IDE/components/CollectionList/CollectionList.jsx b/client/modules/IDE/components/CollectionList/CollectionList.jsx index 69965119ba..afb9555a9a 100644 --- a/client/modules/IDE/components/CollectionList/CollectionList.jsx +++ b/client/modules/IDE/components/CollectionList/CollectionList.jsx @@ -38,10 +38,8 @@ const CollectionList = ({ }) => { const { t } = useTranslation(); const [hasLoadedData, setHasLoadedData] = useState(false); - const [ - addingSketchesToCollectionId, - setAddingSketchesToCollectionId - ] = useState(null); + const [addingSketchesToCollectionId, setAddingSketchesToCollectionId] = + useState(null); useEffect(() => { if (projectId) { diff --git a/client/modules/IDE/components/CollectionList/CollectionListRow.jsx b/client/modules/IDE/components/CollectionList/CollectionListRow.jsx index 6ae24e74e9..e331af1d02 100644 --- a/client/modules/IDE/components/CollectionList/CollectionListRow.jsx +++ b/client/modules/IDE/components/CollectionList/CollectionListRow.jsx @@ -1,279 +1,279 @@ -import PropTypes from 'prop-types'; -import React, { useState, useRef } from 'react'; -import { connect } from 'react-redux'; -import { Link } from 'react-router-dom'; -import { bindActionCreators } from 'redux'; -import { withTranslation } from 'react-i18next'; -import styled from 'styled-components'; -import { MenuItem } from '../../../../components/Dropdown/MenuItem'; -import { TableDropdown } from '../../../../components/Dropdown/TableDropdown'; -import * as ProjectActions from '../../actions/project'; -import * as CollectionsActions from '../../actions/collections'; -import * as IdeActions from '../../actions/ide'; -import * as ToastActions from '../../actions/toast'; -import { formatDateToString } from '../../../../utils/formatDate'; -import { remSize, prop } from '../../../../theme'; - -const SketchsTableRow = styled.tr` - &&& { - margin: ${remSize(10)}; - height: ${remSize(72)}; - font-size: ${remSize(16)}; - } - &:nth-child(odd) { - background: ${prop('tableRowStripeColor')}; - } - - > th:nth-child(1) { - padding-left: ${remSize(12)}; - } - - > td { - padding-left: ${remSize(8)}; - } - - a { - color: ${prop('primaryTextColor')}; - text-decoration: underline; - - &:hover { - text-decoration: underline; - text-decoration-thickness: 0.1em; - } - } - - &.is-deleted > * { - font-style: italic; - } - @media (max-width: 770px) { - &&& { - margin: 0; - position: relative; - display: flex; - flex-wrap: wrap; - padding: ${remSize(15)}; - height: fit-content; - gap: ${remSize(8)}; - border: 1px solid ${prop('modalBorderColor')}; - background-color: ${prop('searchBackgroundColor')}; - > th { - padding-left: 0; - width: 100%; - font-weight: bold; - margin-bottom: ${remSize(6)}; - } - > td { - padding-left: 0; - width: 30%; - font-size: ${remSize(14)}; - color: ${prop('modalBorderColor')}; - } - } - } -`; -const SketchesTableName = styled.span` - &&& { - display: flex; - align-items: center; - } -`; -const SketchlistDropdownColumn = styled.td` - &&& { - position: relative; - width: ${remSize(60)}; - } - @media (max-width: 770px) { - &&& { - position: absolute; - top: 0; - right: ${remSize(4)}; - width: auto !important; - margin: ${remSize(8)}; - } - } -`; -const formatDateCell = (date, mobile = false) => - formatDateToString(date, { showTime: !mobile }); - -const CollectionListRowBase = (props) => { - const [renameOpen, setRenameOpen] = useState(false); - const [renameValue, setRenameValue] = useState(''); - const renameInput = useRef(null); - - const closeAll = () => { - setRenameOpen(false); - }; - - const updateName = () => { - const isValid = renameValue.trim().length !== 0; - if (isValid) { - props.editCollection(props.collection.id, { - name: renameValue.trim() - }); - } - }; - - const handleAddSketches = () => { - closeAll(); - props.onAddSketches(); - }; - - const handleCollectionDelete = () => { - closeAll(); - if ( - window.confirm( - props.t('Common.DeleteConfirmation', { - name: props.collection.name - }) - ) - ) { - props.deleteCollection(props.collection.id); - } - }; - - const handleRenameOpen = () => { - closeAll(); - setRenameOpen(true); - setRenameValue(props.collection.name); - }; - - const handleRenameChange = (e) => { - setRenameValue(e.target.value); - }; - - const handleRenameEnter = (e) => { - if (e.key === 'Enter') { - e.preventDefault(); - updateName(); - closeAll(); - } - }; - - const handleRenameFocus = () => { - if (renameInput.current) { - renameInput.current.focus(); - } - }; - - const handleRenameBlur = () => { - updateName(); - closeAll(); - }; - - const renderActions = () => { - const userIsOwner = props.user.username === props.username; - - return ( - - - {props.t('CollectionListRow.AddSketch')} - - - {props.t('CollectionListRow.Delete')} - - - {props.t('CollectionListRow.Rename')} - - - ); - }; - - const renderCollectionName = () => { - const { collection, username } = props; - - return ( - <> - - {renameOpen ? '' : collection.name} - - {renameOpen && ( - e.stopPropagation()} - ref={(node) => { - renameInput.current = node; - handleRenameFocus(); - }} - /> - )} - - ); - }; - - const { collection, mobile } = props; - - return ( - - - {renderCollectionName()} - - {formatDateCell(collection.createdAt, mobile)} - {formatDateCell(collection.updatedAt, mobile)} - - {mobile && 'sketches: '} - {(collection.items || []).length} - - {renderActions()} - - ); -}; - -CollectionListRowBase.propTypes = { - collection: PropTypes.shape({ - id: PropTypes.string.isRequired, - name: PropTypes.string.isRequired, - owner: PropTypes.shape({ - username: PropTypes.string.isRequired - }).isRequired, - createdAt: PropTypes.string.isRequired, - updatedAt: PropTypes.string.isRequired, - items: PropTypes.arrayOf( - PropTypes.shape({ - project: PropTypes.shape({ - id: PropTypes.string.isRequired - }) - }) - ) - }).isRequired, - username: PropTypes.string.isRequired, - user: PropTypes.shape({ - username: PropTypes.string, - authenticated: PropTypes.bool.isRequired - }).isRequired, - deleteCollection: PropTypes.func.isRequired, - editCollection: PropTypes.func.isRequired, - onAddSketches: PropTypes.func.isRequired, - mobile: PropTypes.bool, - t: PropTypes.func.isRequired -}; - -CollectionListRowBase.defaultProps = { - mobile: false -}; - -function mapDispatchToPropsSketchListRow(dispatch) { - return bindActionCreators( - Object.assign( - {}, - CollectionsActions, - ProjectActions, - IdeActions, - ToastActions - ), - dispatch - ); -} - -export default withTranslation()( - connect(null, mapDispatchToPropsSketchListRow)(CollectionListRowBase) -); +import PropTypes from 'prop-types'; +import React, { useState, useRef } from 'react'; +import { connect } from 'react-redux'; +import { Link } from 'react-router-dom'; +import { bindActionCreators } from 'redux'; +import { withTranslation } from 'react-i18next'; +import styled from 'styled-components'; +import { MenuItem } from '../../../../components/Dropdown/MenuItem'; +import { TableDropdown } from '../../../../components/Dropdown/TableDropdown'; +import * as ProjectActions from '../../actions/project'; +import * as CollectionsActions from '../../actions/collections'; +import * as IdeActions from '../../actions/ide'; +import * as ToastActions from '../../actions/toast'; +import { formatDateToString } from '../../../../utils/formatDate'; +import { remSize, prop } from '../../../../theme'; + +const SketchsTableRow = styled.tr` + &&& { + margin: ${remSize(10)}; + height: ${remSize(72)}; + font-size: ${remSize(16)}; + } + &:nth-child(odd) { + background: ${prop('tableRowStripeColor')}; + } + + > th:nth-child(1) { + padding-left: ${remSize(12)}; + } + + > td { + padding-left: ${remSize(8)}; + } + + a { + color: ${prop('primaryTextColor')}; + text-decoration: underline; + + &:hover { + text-decoration: underline; + text-decoration-thickness: 0.1em; + } + } + + &.is-deleted > * { + font-style: italic; + } + @media (max-width: 770px) { + &&& { + margin: 0; + position: relative; + display: flex; + flex-wrap: wrap; + padding: ${remSize(15)}; + height: fit-content; + gap: ${remSize(8)}; + border: 1px solid ${prop('modalBorderColor')}; + background-color: ${prop('searchBackgroundColor')}; + > th { + padding-left: 0; + width: 100%; + font-weight: bold; + margin-bottom: ${remSize(6)}; + } + > td { + padding-left: 0; + width: 30%; + font-size: ${remSize(14)}; + color: ${prop('modalBorderColor')}; + } + } + } +`; +const SketchesTableName = styled.span` + &&& { + display: flex; + align-items: center; + } +`; +const SketchlistDropdownColumn = styled.td` + &&& { + position: relative; + width: ${remSize(60)}; + } + @media (max-width: 770px) { + &&& { + position: absolute; + top: 0; + right: ${remSize(4)}; + width: auto !important; + margin: ${remSize(8)}; + } + } +`; +const formatDateCell = (date, mobile = false) => + formatDateToString(date, { showTime: !mobile }); + +const CollectionListRowBase = (props) => { + const [renameOpen, setRenameOpen] = useState(false); + const [renameValue, setRenameValue] = useState(''); + const renameInput = useRef(null); + + const closeAll = () => { + setRenameOpen(false); + }; + + const updateName = () => { + const isValid = renameValue.trim().length !== 0; + if (isValid) { + props.editCollection(props.collection.id, { + name: renameValue.trim() + }); + } + }; + + const handleAddSketches = () => { + closeAll(); + props.onAddSketches(); + }; + + const handleCollectionDelete = () => { + closeAll(); + if ( + window.confirm( + props.t('Common.DeleteConfirmation', { + name: props.collection.name + }) + ) + ) { + props.deleteCollection(props.collection.id); + } + }; + + const handleRenameOpen = () => { + closeAll(); + setRenameOpen(true); + setRenameValue(props.collection.name); + }; + + const handleRenameChange = (e) => { + setRenameValue(e.target.value); + }; + + const handleRenameEnter = (e) => { + if (e.key === 'Enter') { + e.preventDefault(); + updateName(); + closeAll(); + } + }; + + const handleRenameFocus = () => { + if (renameInput.current) { + renameInput.current.focus(); + } + }; + + const handleRenameBlur = () => { + updateName(); + closeAll(); + }; + + const renderActions = () => { + const userIsOwner = props.user.username === props.username; + + return ( + + + {props.t('CollectionListRow.AddSketch')} + + + {props.t('CollectionListRow.Delete')} + + + {props.t('CollectionListRow.Rename')} + + + ); + }; + + const renderCollectionName = () => { + const { collection, username } = props; + + return ( + <> + + {renameOpen ? '' : collection.name} + + {renameOpen && ( + e.stopPropagation()} + ref={(node) => { + renameInput.current = node; + handleRenameFocus(); + }} + /> + )} + + ); + }; + + const { collection, mobile } = props; + + return ( + + + {renderCollectionName()} + + {formatDateCell(collection.createdAt, mobile)} + {formatDateCell(collection.updatedAt, mobile)} + + {mobile && 'sketches: '} + {(collection.items || []).length} + + {renderActions()} + + ); +}; + +CollectionListRowBase.propTypes = { + collection: PropTypes.shape({ + id: PropTypes.string.isRequired, + name: PropTypes.string.isRequired, + owner: PropTypes.shape({ + username: PropTypes.string.isRequired + }).isRequired, + createdAt: PropTypes.string.isRequired, + updatedAt: PropTypes.string.isRequired, + items: PropTypes.arrayOf( + PropTypes.shape({ + project: PropTypes.shape({ + id: PropTypes.string.isRequired + }) + }) + ) + }).isRequired, + username: PropTypes.string.isRequired, + user: PropTypes.shape({ + username: PropTypes.string, + authenticated: PropTypes.bool.isRequired + }).isRequired, + deleteCollection: PropTypes.func.isRequired, + editCollection: PropTypes.func.isRequired, + onAddSketches: PropTypes.func.isRequired, + mobile: PropTypes.bool, + t: PropTypes.func.isRequired +}; + +CollectionListRowBase.defaultProps = { + mobile: false +}; + +function mapDispatchToPropsSketchListRow(dispatch) { + return bindActionCreators( + Object.assign( + {}, + CollectionsActions, + ProjectActions, + IdeActions, + ToastActions + ), + dispatch + ); +} + +export default withTranslation()( + connect(null, mapDispatchToPropsSketchListRow)(CollectionListRowBase) +); diff --git a/client/modules/IDE/components/Console.jsx b/client/modules/IDE/components/Console.jsx index 3494fccdee..181ca7c362 100644 --- a/client/modules/IDE/components/Console.jsx +++ b/client/modules/IDE/components/Console.jsx @@ -30,10 +30,10 @@ const Console = () => { cm.current.scrollTop = cm.current.scrollHeight; }); - const consoleFeedStyle = useMemo(() => getConsoleFeedStyle(theme, fontSize), [ - theme, - fontSize - ]); + const consoleFeedStyle = useMemo( + () => getConsoleFeedStyle(theme, fontSize), + [theme, fontSize] + ); const handleMessageEvent = useHandleMessageEvent(); diff --git a/client/modules/IDE/components/ErrorModal.jsx b/client/modules/IDE/components/ErrorModal.jsx index 66dd374c52..435cf53c94 100644 --- a/client/modules/IDE/components/ErrorModal.jsx +++ b/client/modules/IDE/components/ErrorModal.jsx @@ -53,7 +53,8 @@ const ErrorModal = ({ type, service, closeModal }) => { return (
- {(() => { // eslint-disable-line + {(() => { + // eslint-disable-line if (type === 'forceAuthentication') { return forceAuthentication(); } else if (type === 'staleSession') { @@ -63,6 +64,7 @@ const ErrorModal = ({ type, service, closeModal }) => { } else if (type === 'oauthError') { return oauthError(); } + return null; })()}
); diff --git a/client/modules/IDE/components/FileNode.jsx b/client/modules/IDE/components/FileNode.jsx index cb872eb982..08a5cabf19 100644 --- a/client/modules/IDE/components/FileNode.jsx +++ b/client/modules/IDE/components/FileNode.jsx @@ -1,15 +1,15 @@ import PropTypes from 'prop-types'; import classNames from 'classnames'; import React, { useState, useRef } from 'react'; -import { connect } from 'react-redux'; +import { connect, useSelector } from 'react-redux'; import { useTranslation } from 'react-i18next'; -import { useSelector } from 'react-redux'; import * as IDEActions from '../actions/ide'; import * as FileActions from '../actions/files'; import DownArrowIcon from '../../../images/down-filled-triangle.svg'; import FolderRightIcon from '../../../images/triangle-arrow-right.svg'; import FolderDownIcon from '../../../images/triangle-arrow-down.svg'; +import LockIcon from '../../../images/lock.svg'; import FileTypeIcon from './FileTypeIcon'; function parseFileName(name) { @@ -20,33 +20,18 @@ function parseFileName(name) { const firstLetter = baseName[0]; const lastLetter = baseName[baseName.length - 1]; const middleText = baseName.slice(1, -1); - return { - baseName, - firstLetter, - lastLetter, - middleText, - extension - }; + return { baseName, firstLetter, lastLetter, middleText, extension }; } const firstLetter = name[0]; const lastLetter = name[name.length - 1]; const middleText = name.slice(1, -1); - return { - baseName: name, - firstLetter, - lastLetter, - middleText - }; + return { baseName: name, firstLetter, lastLetter, middleText }; } function FileName({ name }) { - const { - baseName, - firstLetter, - lastLetter, - middleText, - extension - } = parseFileName(name); + const { baseName, firstLetter, lastLetter, middleText, extension } = + parseFileName(name); + return ( {firstLetter} @@ -59,9 +44,7 @@ function FileName({ name }) { ); } -FileName.propTypes = { - name: PropTypes.string.isRequired -}; +FileName.propTypes = { name: PropTypes.string.isRequired }; const FileNode = ({ id, @@ -90,6 +73,9 @@ const FileNode = ({ const [updatedName, setUpdatedName] = useState(name); const files = useSelector((state) => state.files); + const { t } = useTranslation(); + const fileNameInput = useRef(null); + const fileOptionsRef = useRef(null); const checkDuplicate = (newName) => { const parentFolder = files.find((f) => f.id === parentId); @@ -100,54 +86,38 @@ const FileNode = ({ .filter(Boolean) .filter((file) => file.id !== id); - const isDuplicate = siblingFiles.some( + return siblingFiles.some( (f) => f.name.trim().toLowerCase() === newName.trim().toLowerCase() ); - - return isDuplicate; }; - const { t } = useTranslation(); - const fileNameInput = useRef(null); - const fileOptionsRef = useRef(null); - const handleFileClick = (event) => { event.stopPropagation(); - if (name !== 'root' && !isDeleting) { - setSelectedFile(id); - } - if (onClickFile) { - onClickFile(); - } - }; - - const handleFileNameChange = (event) => { - setUpdatedName(event.target.value); + if (name !== 'root' && !isDeleting) setSelectedFile(id); + if (onClickFile) onClickFile(); }; - const showEditFileName = () => { - setIsEditingName(true); - }; + const handleFileNameChange = (event) => setUpdatedName(event.target.value); - const hideFileOptions = () => { - setIsOptionsOpen(false); - }; + const showEditFileName = () => setIsEditingName(true); + const hideEditFileName = () => setIsEditingName(false); + const hideFileOptions = () => setIsOptionsOpen(false); const handleClickRename = () => { setUpdatedName(name); showEditFileName(); setTimeout(() => fileNameInput.current.focus(), 0); - setTimeout(() => hideFileOptions(), 0); + setTimeout(hideFileOptions, 0); }; const handleClickAddFile = () => { newFile(id); - setTimeout(() => hideFileOptions(), 0); + setTimeout(hideFileOptions, 0); }; const handleClickAddFolder = () => { newFolder(id); - setTimeout(() => hideFileOptions(), 0); + setTimeout(hideFileOptions, 0); }; const handleClickUploadFile = () => { @@ -157,7 +127,6 @@ const FileNode = ({ const handleClickDelete = () => { const prompt = t('Common.DeleteConfirmation', { name }); - if (window.confirm(prompt)) { setIsDeleting(true); resetSelectedFile(id); @@ -165,14 +134,8 @@ const FileNode = ({ } }; - const hideEditFileName = () => { - setIsEditingName(false); - }; - const handleKeyPress = (event) => { - if (event.key === 'Enter') { - hideEditFileName(); - } + if (event.key === 'Enter') hideEditFileName(); }; const saveUpdatedFileName = () => { @@ -195,6 +158,7 @@ const FileNode = ({ const hasEmptyFilename = updatedName.trim() === ''; const hasOnlyExtension = newFileExtension && updatedName.trim() === newFileExtension[0]; + if ( hasEmptyFilename || hasNoExtension || @@ -206,14 +170,9 @@ const FileNode = ({ const userResponse = window.confirm( 'Are you sure you want to change the file extension?' ); - if (userResponse) { - saveUpdatedFileName(); - } else { - setUpdatedName(currentName); - } - } else { - saveUpdatedFileName(); - } + if (userResponse) saveUpdatedFileName(); + else setUpdatedName(currentName); + } else saveUpdatedFileName(); }; const handleFileNameBlur = () => { @@ -228,9 +187,7 @@ const FileNode = ({ const toggleFileOptions = (event) => { event.preventDefault(); - if (!canEdit) { - return; - } + if (!canEdit) return; setIsOptionsOpen(!isOptionsOpen); }; @@ -246,14 +203,13 @@ const FileNode = ({ const isFile = fileType === 'file'; const isFolder = fileType === 'folder'; const isRoot = name === 'root'; - const { extension } = parseFileName(name); return (
{!isRoot && (
- + {isFile && ( setTimeout(hideFileOptions, 200)} > @@ -343,34 +299,52 @@ const FileNode = ({ {t('FileNode.AddFile')} - {authenticated && ( -
  • - -
  • - )} +
  • + +
  • +
  • + +
  • +
  • + +
  • )} -
  • - -
  • -
  • - -
  • @@ -423,14 +397,11 @@ FileNode.defaultProps = { }; function mapStateToProps(state, ownProps) { - // this is a hack, state is updated before ownProps const fileNode = state.files.find((file) => file.id === ownProps.id) || { name: 'test', fileType: 'file' }; - return Object.assign({}, fileNode, { - authenticated: state.user.authenticated - }); + return { ...fileNode, authenticated: state.user.authenticated }; } const mapDispatchToProps = { ...FileActions, ...IDEActions }; diff --git a/client/modules/IDE/components/Header/Nav.jsx b/client/modules/IDE/components/Header/Nav.jsx index 28995a2d56..4584e452f8 100644 --- a/client/modules/IDE/components/Header/Nav.jsx +++ b/client/modules/IDE/components/Header/Nav.jsx @@ -162,12 +162,8 @@ const ProjectMenu = () => { const dispatch = useDispatch(); const { t } = useTranslation(); - const { - newSketch, - saveSketch, - downloadSketch, - shareSketch - } = useSketchActions(); + const { newSketch, saveSketch, downloadSketch, shareSketch } = + useSketchActions(); const replaceCommand = metaKey === 'Ctrl' ? `${metaKeyName}+H` : `${metaKeyName}+⌥+F`; diff --git a/client/modules/IDE/components/Sidebar.jsx b/client/modules/IDE/components/Sidebar.jsx index 24fd487c9a..8dcad92529 100644 --- a/client/modules/IDE/components/Sidebar.jsx +++ b/client/modules/IDE/components/Sidebar.jsx @@ -14,17 +14,14 @@ import { selectRootFile } from '../selectors/files'; import { getAuthenticated, selectCanEditSketch } from '../selectors/users'; import ConnectedFileNode from './FileNode'; -import { PlusIcon } from '../../../common/icons'; +import { PlusIcon, LockIcon } from '../../../common/icons'; import { FileDrawer } from './Editor/MobileEditor'; -// TODO: use a generic Dropdown UI component - export default function SideBar() { const { t } = useTranslation(); const dispatch = useDispatch(); const rootFile = useSelector(selectRootFile); - const ide = useSelector((state) => state.ide); const projectOptionsVisible = useSelector( (state) => state.ide.projectOptionsVisible ); @@ -58,11 +55,8 @@ export default function SideBar() { const toggleProjectOptions = (e) => { e.preventDefault(); - if (projectOptionsVisible) { - dispatch(closeProjectOptions()); - } else { - dispatch(openProjectOptions()); - } + if (projectOptionsVisible) dispatch(closeProjectOptions()); + else dispatch(openProjectOptions()); }; const sidebarClass = classNames({ @@ -74,7 +68,7 @@ export default function SideBar() { return ( - {ide.sidebarIsExpanded && ( + {isExpanded && ( - {isAuthenticated && ( -
  • - -
  • - )} + } + }} + > + {!isAuthenticated && ( + + + )} + {t('Sidebar.UploadFile')} + {!isAuthenticated && ( + + {t('Sidebar.UploadFileRequiresLogin')} + + )} + + )} diff --git a/client/modules/IDE/reducers/editorAccessibility.js b/client/modules/IDE/reducers/editorAccessibility.js index 94cc9ac54f..b0ba3ea6f1 100644 --- a/client/modules/IDE/reducers/editorAccessibility.js +++ b/client/modules/IDE/reducers/editorAccessibility.js @@ -29,10 +29,7 @@ const editorAccessibilitySlice = createSlice({ } }); -export const { - updateLintMessage, - clearLintMessage, - toggleForceDesktop -} = editorAccessibilitySlice.actions; +export const { updateLintMessage, clearLintMessage, toggleForceDesktop } = + editorAccessibilitySlice.actions; export default editorAccessibilitySlice.reducer; diff --git a/client/modules/Preview/EmbedFrame.jsx b/client/modules/Preview/EmbedFrame.jsx index 2b6ac16720..09790ecc03 100644 --- a/client/modules/Preview/EmbedFrame.jsx +++ b/client/modules/Preview/EmbedFrame.jsx @@ -232,9 +232,10 @@ p5.prototype.registerMethod('afterSetup', p5.prototype.ensureAccessibleCanvas);` } const previewScripts = sketchDoc.createElement('script'); - previewScripts.src = `${ - window.location.origin - }${getConfig('PREVIEW_SCRIPTS_URL', { nullishString: true })}`; + previewScripts.src = `${window.location.origin}${getConfig( + 'PREVIEW_SCRIPTS_URL', + { nullishString: true } + )}`; previewScripts.setAttribute('crossorigin', ''); sketchDoc.head.appendChild(previewScripts); diff --git a/client/routes.jsx b/client/routes.jsx index 2195d95da2..bde0e8381d 100644 --- a/client/routes.jsx +++ b/client/routes.jsx @@ -26,10 +26,11 @@ import ProtectedSketchRoute from './protected-route'; * It is a nested property of `match`. * Use an HOC to lift it up to top-level. */ -const withParams = (Component) => (props) => ( - // eslint-disable-next-line react/prop-types - -); +const withParams = (Component) => (props) => + ( + // eslint-disable-next-line react/prop-types + + ); /** * Instead of updating all individual components, use this plug-in Route replacement. * It passes the `params` as a top-level property diff --git a/client/styles/abstracts/_functions.scss b/client/styles/abstracts/_functions.scss index a4756f0803..57a5615086 100644 --- a/client/styles/abstracts/_functions.scss +++ b/client/styles/abstracts/_functions.scss @@ -2,16 +2,15 @@ $key: nth($keys, 1); $length: length($keys); $value: map-get($map, $key); - - + @if $value != null { @if $length > 1 { $rest: (); - + @for $i from 2 through $length { - $rest: append($rest, nth($keys, $i)) + $rest: append($rest, nth($keys, $i)); } - + @return map-fetch($value, $rest); } @else { @return $value; @@ -23,4 +22,4 @@ @function getThemifyVariable($key) { @return map-get($theme-map, $key); -} \ No newline at end of file +} diff --git a/client/styles/abstracts/_mixins.scss b/client/styles/abstracts/_mixins.scss index 2bbd8dd3ab..84e2ee38f6 100644 --- a/client/styles/abstracts/_mixins.scss +++ b/client/styles/abstracts/_mixins.scss @@ -1,17 +1,21 @@ -@mixin themify ($themes: $themes) { +@mixin themify($themes: $themes) { @each $theme, $map in $themes { .#{$theme} & { // Define theme color - $theme-map : ( - ) !global; - + $theme-map: () !global; + @each $key, $submap in $map { $value: map-fetch($themes, $theme '#{$key}'); - $theme-map: map-merge($theme-map, ($key: $value)) !global; - } - + $theme-map: map-merge( + $theme-map, + ( + $key: $value + ) + ) !global; + } + @content; - + // reset theme color to null $theme-map: null !global; } @@ -21,13 +25,17 @@ @mixin icon() { @include themify() { color: getThemifyVariable('icon-color'); - & g, & polygon, & path { + & g, + & polygon, + & path { opacity: 1; fill: getThemifyVariable('icon-color'); } &:hover { color: getThemifyVariable('icon-hover-color'); - & g, & polygon, & path { + & g, + & polygon, + & path { opacity: 1; fill: getThemifyVariable('icon-hover-color'); } @@ -37,4 +45,4 @@ border: none; cursor: pointer; padding: 0; -} \ No newline at end of file +} diff --git a/client/styles/abstracts/_placeholders.scss b/client/styles/abstracts/_placeholders.scss index 65e115a38a..ec4bad638a 100644 --- a/client/styles/abstracts/_placeholders.scss +++ b/client/styles/abstracts/_placeholders.scss @@ -1,249 +1,272 @@ -@use "sass:math"; +@use 'sass:math'; %toolbar-button { - @include themify() { - display: inline-block; - height: #{math.div(44, $base-font-size)}rem; - width: #{math.div(44, $base-font-size)}rem; - text-align: center; - border-radius: 100%; - cursor: pointer; - border: none; - outline: none; - background-color: getThemifyVariable('toolbar-button-background-color'); - color: getThemifyVariable('toolbar-button-color'); - & g, & path { - fill: getThemifyVariable('toolbar-button-color'); - } - &:hover { - background-color: getThemifyVariable('button-background-hover-color'); - color: getThemifyVariable('button-hover-color'); + @include themify() { + display: inline-block; + height: #{math.div(44, $base-font-size)}rem; + width: #{math.div(44, $base-font-size)}rem; + text-align: center; + border-radius: 100%; + cursor: pointer; + border: none; + outline: none; + background-color: getThemifyVariable('toolbar-button-background-color'); + color: getThemifyVariable('toolbar-button-color'); + & g, + & path { + fill: getThemifyVariable('toolbar-button-color'); + } + &:hover { + background-color: getThemifyVariable('button-background-hover-color'); + color: getThemifyVariable('button-hover-color'); - & g, & path { - fill: getThemifyVariable('button-hover-color'); - } - } - &--selected { - background-color: getThemifyVariable('button-background-hover-color'); - & g, & path { - fill: getThemifyVariable('button-hover-color'); - } - } - } + & g, + & path { + fill: getThemifyVariable('button-hover-color'); + } + } + &--selected { + background-color: getThemifyVariable('button-background-hover-color'); + & g, + & path { + fill: getThemifyVariable('button-hover-color'); + } + } + } } -%icon-toast{ - @include themify() { - color: $toast-text-color - & g, & path { - fill: $toast-text-color - } - &:hover { - color: getThemifyVariable('icon-toast-hover-color'); - & g, & path { - opacity: 1; - fill: getThemifyVariable('icon-toast-hover-color'); - } - } - } - background-color: transparent; - border: none; - cursor: pointer; - padding: 0; +%icon-toast { + @include themify() { + color: $toast-text-color & g, & path { + fill: $toast-text-color; + } + &:hover { + color: getThemifyVariable('icon-toast-hover-color'); + & g, + & path { + opacity: 1; + fill: getThemifyVariable('icon-toast-hover-color'); + } + } + } + background-color: transparent; + border: none; + cursor: pointer; + padding: 0; } %none-themify-icon { - background-color: transparent; - border: none; - cursor: pointer; - padding: 0; + background-color: transparent; + border: none; + cursor: pointer; + padding: 0; } %none-themify-icon-with-hover { - color: $medium-dark; - & g, & path { - fill: $medium-dark; - } - &:hover { - color: $p5js-pink; - & g, & path { - opacity: 1; - fill: $p5js-pink; - } - } - background-color: transparent; - border: none; - cursor: pointer; - padding: 0; + color: $medium-dark; + & g, + & path { + fill: $medium-dark; + } + &:hover { + color: $p5js-pink; + & g, + & path { + opacity: 1; + fill: $p5js-pink; + } + } + background-color: transparent; + border: none; + cursor: pointer; + padding: 0; } %button { - @include themify() { - background-color: getThemifyVariable('button-background-color'); - color: getThemifyVariable('button-color'); - cursor: pointer; - border: 2px solid getThemifyVariable('button-border-color'); - border-radius: 2px; - padding: #{math.div(10, $base-font-size)}rem #{math.div(30, $base-font-size)}rem; - & g, & path { - fill: getThemifyVariable('button-color'); - opacity: 1; - } - &:not(disabled):hover { - border-color: getThemifyVariable('button-background-hover-color'); - background-color: getThemifyVariable('button-background-hover-color'); - color: getThemifyVariable('button-hover-color'); - & g, & path { - fill: getThemifyVariable('button-hover-color'); - } - } - &:not(disabled):active { - border-color: getThemifyVariable('button-background-active-color'); - background-color: getThemifyVariable('button-background-active-color'); - color: getThemifyVariable('button-active-color'); - & g, & path { - fill: getThemifyVariable('button-active-color'); - } - } - } + @include themify() { + background-color: getThemifyVariable('button-background-color'); + color: getThemifyVariable('button-color'); + cursor: pointer; + border: 2px solid getThemifyVariable('button-border-color'); + border-radius: 2px; + padding: #{math.div(10, $base-font-size)}rem #{math.div(30, $base-font-size)}rem; + & g, + & path { + fill: getThemifyVariable('button-color'); + opacity: 1; + } + &:not(disabled):hover { + border-color: getThemifyVariable('button-background-hover-color'); + background-color: getThemifyVariable('button-background-hover-color'); + color: getThemifyVariable('button-hover-color'); + & g, + & path { + fill: getThemifyVariable('button-hover-color'); + } + } + &:not(disabled):active { + border-color: getThemifyVariable('button-background-active-color'); + background-color: getThemifyVariable('button-background-active-color'); + color: getThemifyVariable('button-active-color'); + & g, + & path { + fill: getThemifyVariable('button-active-color'); + } + } + } } %preferences-button { - @extend %toolbar-button; - @include themify() { - color: getThemifyVariable('primary-text-color'); - background-color: getThemifyVariable('preferences-button-background-color'); - padding: 0; - margin-bottom: #{math.div(28, $base-font-size)}rem; - line-height: #{math.div(50, $base-font-size)}rem; - & g, & path { - fill: getThemifyVariable('modal-button-color'); - } - &:enabled:hover { - background-color: getThemifyVariable('button-background-hover-color'); - color: getThemifyVariable('button-hover-color'); - & g, & path { - fill: getThemifyVariable('button-hover-color'); - } - } - &:disabled:hover { - cursor: not-allowed; - background-color: getThemifyVariable('preferences-button-background-color'); - } - } + @extend %toolbar-button; + @include themify() { + color: getThemifyVariable('primary-text-color'); + background-color: getThemifyVariable('preferences-button-background-color'); + padding: 0; + margin-bottom: #{math.div(28, $base-font-size)}rem; + line-height: #{math.div(50, $base-font-size)}rem; + & g, + & path { + fill: getThemifyVariable('modal-button-color'); + } + &:enabled:hover { + background-color: getThemifyVariable('button-background-hover-color'); + color: getThemifyVariable('button-hover-color'); + & g, + & path { + fill: getThemifyVariable('button-hover-color'); + } + } + &:disabled:hover { + cursor: not-allowed; + background-color: getThemifyVariable( + 'preferences-button-background-color' + ); + } + } } %preference-option { - @include themify() { - background-color: transparent; - color: getThemifyVariable('inactive-text-color'); - &:hover { - color: getThemifyVariable('heavy-text-color'); - } - } - font-size: #{math.div(12, $base-font-size)}rem; - cursor: pointer; - text-align: left; - padding: 0; - margin-bottom: #{math.div(5, $base-font-size)}rem; - padding-right: #{math.div(5, $base-font-size)}rem; - border: 0; - list-style-type: none; + @include themify() { + background-color: transparent; + color: getThemifyVariable('inactive-text-color'); + &:hover { + color: getThemifyVariable('heavy-text-color'); + } + } + font-size: #{math.div(12, $base-font-size)}rem; + cursor: pointer; + text-align: left; + padding: 0; + margin-bottom: #{math.div(5, $base-font-size)}rem; + padding-right: #{math.div(5, $base-font-size)}rem; + border: 0; + list-style-type: none; } %modal { - @include themify() { - background-color: getThemifyVariable('modal-background-color'); - border: 1px solid getThemifyVariable('modal-border-color'); - box-shadow: 0 12px 12px getThemifyVariable('shadow-color'); - } - border-radius: 2px; - z-index: 20; + @include themify() { + background-color: getThemifyVariable('modal-background-color'); + border: 1px solid getThemifyVariable('modal-border-color'); + box-shadow: 0 12px 12px getThemifyVariable('shadow-color'); + } + border-radius: 2px; + z-index: 20; } %hidden-element { - position:absolute; - left:-10000px; - top:auto; - width:1px; - height:1px; - overflow:hidden; + position: absolute; + left: -10000px; + top: auto; + width: 1px; + height: 1px; + overflow: hidden; } - %link { - @include themify() { - text-decoration: none; - color: getThemifyVariable('inactive-text-color'); - cursor: pointer; - & g, & path { - fill: getThemifyVariable('inactive-text-color'); - } - &:hover { - text-decoration: none; - color: getThemifyVariable('heavy-text-color'); - & g, & path { - fill: getThemifyVariable('heavy-text-color'); - } - } - } + @include themify() { + text-decoration: none; + color: getThemifyVariable('inactive-text-color'); + cursor: pointer; + & g, + & path { + fill: getThemifyVariable('inactive-text-color'); + } + &:hover { + text-decoration: none; + color: getThemifyVariable('heavy-text-color'); + & g, + & path { + fill: getThemifyVariable('heavy-text-color'); + } + } + } } %dropdown-open { - @include themify() { + @include themify() { background-color: map-get($theme-map, 'modal-background-color'); border: 1px solid map-get($theme-map, 'modal-border-color'); box-shadow: 0 0 18px 0 getThemifyVariable('shadow-color'); color: getThemifyVariable('primary-text-color'); - } - text-align: left; - width: #{math.div(180, $base-font-size)}rem; - display: flex; - position: absolute; - flex-direction: column; - top: 95%; - height: auto; - z-index: 9999; - border-radius: #{math.div(6, $base-font-size)}rem; - & li:first-child { - border-radius: #{math.div(5, $base-font-size)}rem #{math.div(5, $base-font-size)}rem 0 0; - } - & li:last-child { - border-radius: 0 0 #{math.div(5, $base-font-size)}rem #{math.div(5, $base-font-size)}rem; - } - & li { - & button, - & a { - @include themify() { - color: getThemifyVariable('primary-text-color'); - } - width: 100%; - text-align: left; - padding: #{math.div(8, $base-font-size)}rem #{math.div(16, $base-font-size)}rem; - } - height: #{math.div(35, $base-font-size)}rem; - cursor: pointer; - display: flex; - align-items: center; - } - & li:hover { - @include themify() { + } + text-align: left; + width: #{math.div(180, $base-font-size)}rem; + display: flex; + position: absolute; + flex-direction: column; + top: 95%; + height: auto; + z-index: 9999; + border-radius: #{math.div(6, $base-font-size)}rem; + & li:first-child { + border-radius: #{math.div(5, $base-font-size)}rem #{math.div( + 5, + $base-font-size + )}rem 0 0; + } + & li:last-child { + border-radius: 0 0 #{math.div(5, $base-font-size)}rem #{math.div( + 5, + $base-font-size + )}rem; + } + & li { + & button, + & a { + @include themify() { + color: getThemifyVariable('primary-text-color'); + } + width: 100%; + text-align: left; + padding: #{math.div(8, $base-font-size)}rem #{math.div( + 16, + $base-font-size + )}rem; + } + height: #{math.div(35, $base-font-size)}rem; + cursor: pointer; + display: flex; + align-items: center; + } + & li:hover { + @include themify() { background-color: getThemifyVariable('button-background-hover-color'); - color: getThemifyVariable('button-hover-color') - } - & button, & a { + color: getThemifyVariable('button-hover-color'); + } + & button, + & a { @include themify() { color: getThemifyVariable('button-hover-color'); } } - } + } } %dropdown-open-left { - @extend %dropdown-open; - left: 0; + @extend %dropdown-open; + left: 0; } %dropdown-open-right { - @extend %dropdown-open; - right: 0; + @extend %dropdown-open; + right: 0; } diff --git a/client/styles/abstracts/_variables.scss b/client/styles/abstracts/_variables.scss index 361ad57a38..a2f03cdf14 100644 --- a/client/styles/abstracts/_variables.scss +++ b/client/styles/abstracts/_variables.scss @@ -6,27 +6,27 @@ $p5js-pink-opacity: #ed225d80; $p5js-active-pink: #f10046; $white: #fff; $black: #000; -$yellow: #F5DC23; -$dodgerblue: #1E90FF; -$p5-contrast-pink: #FFA9D9; +$yellow: #f5dc23; +$dodgerblue: #1e90ff; +$p5-contrast-pink: #ffa9d9; -$outline-color: #0F9DD7; +$outline-color: #0f9dd7; // Grayscale values -$lightest: #FFF; // primary -$lighter: #FBFBFB; +$lightest: #fff; // primary +$lighter: #fbfbfb; -$light: #F0F0F0; // primary -$medium-light: #D9D9D9; -$middle-light: #A6A6A6; +$light: #f0f0f0; // primary +$medium-light: #d9d9d9; +$middle-light: #a6a6a6; // $middle-gray: #7D7D7D; // primary $middle-gray: #747474; // primary $middle-dark: #666; -$medium-dark: #4D4D4D; +$medium-dark: #4d4d4d; $dark: #333; // primary -$darker: #1C1C1C; +$darker: #1c1c1c; $darkest: #000; $themes: ( @@ -61,7 +61,7 @@ $themes: ( console-input-background-color: $lightest, console-color: $darker, console-arrow-color: $middle-gray, - console-active-arrow-color: #0071AD, + console-active-arrow-color: #0071ad, console-header-background-color: $medium-light, console-header-color: $darker, ide-border-color: $medium-light, @@ -84,14 +84,14 @@ $themes: ( error-color: $p5js-pink, table-row-stripe-color: $medium-light, table-row-stripe-color-alternate: $medium-light, - codefold-icon-open: url("../images/triangle-arrow-down.svg?byUrl"), - codefold-icon-closed: url("../images/triangle-arrow-right.svg?byUrl"), + codefold-icon-open: url('../images/triangle-arrow-down.svg?byUrl'), + codefold-icon-closed: url('../images/triangle-arrow-right.svg?byUrl'), preferences-warning-color: $p5js-pink, table-button-color: $lightest, table-button-background-color: $middle-gray, table-button-active-color: $lightest, - table-button-background-active-color: #00A1D3, + table-button-background-active-color: #00a1d3, table-button-hover-color: $lightest, table-button-background-hover-color: $p5js-pink, @@ -107,9 +107,9 @@ $themes: ( hint-background-color: $white, hint-text-color: $dark, hint-item-border-bottom-color: $white, - hint-fun-text-color: #0B7CA9, - hint-var-text-color: #D52889, - hint-keyword-text-color: #7A5A3A, + hint-fun-text-color: #0b7ca9, + hint-var-text-color: #d52889, + hint-keyword-text-color: #7a5a3a, hint-type-text-color: $medium-dark, hint-arrow-color: $lightest, hint-arrow-background-color: #ed225ddd, @@ -119,17 +119,17 @@ $themes: ( hint-item-hover-background-color: #f4f4f4, hint-item-active-text-color: $white, hint-item-active-background-color: $middle-gray, - hint-fun-active-border-bottom-color: #0B7CA9, - hint-var-active-border-bottom-color: #D52889, + hint-fun-active-border-bottom-color: #0b7ca9, + hint-var-active-border-bottom-color: #d52889, hint-item-active-type-text-color: $white, hint-item-active-outline: none, hint-item-active-outline-offset: 0, hint-inline-text-color-light: $middle-light, hint-inline-text-color: $middle-gray, - admonition-border: #22C8ED, - admonition-background: #E4F8FF, - admonition-text: #075769, + admonition-border: #22c8ed, + admonition-background: #e4f8ff, + admonition-text: #075769 ), dark: ( logo-color: $p5js-pink, @@ -162,7 +162,7 @@ $themes: ( console-input-background-color: $darker, console-color: $lightest, console-arrow-color: $medium-light, - console-active-arrow-color: #097BB3, + console-active-arrow-color: #097bb3, console-header-background-color: $medium-dark, console-header-color: $lightest, ide-border-color: $middle-dark, @@ -185,14 +185,14 @@ $themes: ( error-color: $p5js-pink, table-row-stripe-color: $dark, table-row-stripe-color-alternate: $darker, - codefold-icon-open: url("../images/triangle-arrow-down-white.svg?byUrl"), - codefold-icon-closed: url("../images/triangle-arrow-right-white.svg?byUrl"), + codefold-icon-open: url('../images/triangle-arrow-down-white.svg?byUrl'), + codefold-icon-closed: url('../images/triangle-arrow-right-white.svg?byUrl'), preferences-warning-color: $yellow, table-button-color: $lightest, table-button-background-color: $middle-gray, table-button-active-color: $lightest, - table-button-background-active-color: #00A1D3, + table-button-background-active-color: #00a1d3, table-button-hover-color: $lightest, table-button-background-hover-color: $p5js-pink, @@ -206,9 +206,9 @@ $themes: ( hint-background-color: $darker, hint-text-color: $light, hint-item-border-bottom-color: $darker, - hint-fun-text-color: #0F9DD7, - hint-var-text-color: #DE4A9B, - hint-keyword-text-color: #B58318, + hint-fun-text-color: #0f9dd7, + hint-var-text-color: #de4a9b, + hint-keyword-text-color: #b58318, hint-type-text-color: $light, hint-arrow-color: $lightest, hint-arrow-background-color: #ed225ddd, @@ -218,17 +218,17 @@ $themes: ( hint-item-hover-background-color: $medium-dark, hint-item-active-text-color: $darker, hint-item-active-background-color: #cfcfcf, - hint-fun-active-border-bottom-color: #0F9DD7, - hint-var-active-border-bottom-color: #DE4A9B, + hint-fun-active-border-bottom-color: #0f9dd7, + hint-var-active-border-bottom-color: #de4a9b, hint-item-active-type-text-color: $darker, hint-item-active-outline: none, hint-item-active-outline-offset: 0, hint-inline-text-color-light: $middle-gray, hint-inline-text-color: #cfcfcf, - admonition-border: #22C8ED, - admonition-background: #105A7F, - admonition-text: #FFFFFF, + admonition-border: #22c8ed, + admonition-background: #105a7f, + admonition-text: #ffffff ), contrast: ( logo-color: $yellow, @@ -284,14 +284,14 @@ $themes: ( error-color: $p5-contrast-pink, table-row-stripe-color: $dark, table-row-stripe-color-alternate: $darker, - codefold-icon-open: url("../images/triangle-arrow-down-white.svg?byUrl"), - codefold-icon-closed: url("../images/triangle-arrow-right-white.svg?byUrl"), + codefold-icon-open: url('../images/triangle-arrow-down-white.svg?byUrl'), + codefold-icon-closed: url('../images/triangle-arrow-right-white.svg?byUrl'), preferences-warning-color: $yellow, table-button-color: $dark, table-button-background-color: $middle-gray, table-button-active-color: $dark, - table-button-background-active-color: #00FFFF, + table-button-background-active-color: #00ffff, table-button-hover-color: $dark, table-button-background-hover-color: $yellow, @@ -305,13 +305,13 @@ $themes: ( hint-background-color: $darkest, hint-text-color: $medium-light, hint-item-border-bottom-color: $medium-dark, - hint-fun-text-color: #00FFFF, - hint-var-text-color: #FFA9D9, - hint-keyword-text-color: #F5DC23, + hint-fun-text-color: #00ffff, + hint-var-text-color: #ffa9d9, + hint-keyword-text-color: #f5dc23, hint-type-text-color: $middle-light, hint-arrow-color: $darker, - hint-arrow-background-color: #F5DC23DD, - hint-arrow-background-active-color: #F5DC23, + hint-arrow-background-color: #f5dc23dd, + hint-arrow-background-active-color: #f5dc23, hint-arrow-focus-outline-color: $lighter, hint-no-link-background-color: $medium-dark, hint-item-hover-background-color: $dark, @@ -325,12 +325,11 @@ $themes: ( hint-inline-text-color-light: $middle-gray, hint-inline-text-color: #cfcfcf, - admonition-border: #22C8ED, + admonition-border: #22c8ed, admonition-background: #000000, - admonition-text: #ffffff, + admonition-text: #ffffff ) ); $toast-background-color: $medium-dark; $toast-text-color: $lightest; - diff --git a/client/styles/base/_base.scss b/client/styles/base/_base.scss index 90e11ba208..17c364e16f 100644 --- a/client/styles/base/_base.scss +++ b/client/styles/base/_base.scss @@ -1,160 +1,158 @@ -@use "sass:math"; +@use 'sass:math'; * { - box-sizing: border-box; + box-sizing: border-box; } html, body { - font-size: #{$base-font-size}px; + font-size: #{$base-font-size}px; } - /* Styles for non-touch devices */ @media (hover: hover) and (pointer: fine) { - /*Scrollbar theming */ - /* width */ - ::-webkit-scrollbar { - width: 10px; - } - /* Track */ - ::-webkit-scrollbar-track { - @include themify() { - color: getThemifyVariable("modal-border-color"); - } - } - /* Handle */ - ::-webkit-scrollbar-thumb { - background: #888; - } - /* Handle on hover */ - ::-webkit-scrollbar-thumb:hover { - background: #555; - } + /*Scrollbar theming */ + /* width */ + ::-webkit-scrollbar { + width: 10px; + } + /* Track */ + ::-webkit-scrollbar-track { + @include themify() { + color: getThemifyVariable('modal-border-color'); + } + } + /* Handle */ + ::-webkit-scrollbar-thumb { + background: #888; + } + /* Handle on hover */ + ::-webkit-scrollbar-thumb:hover { + background: #555; + } } body, input, textarea { - @include themify() { - color: getThemifyVariable("primary-text-color"); - } + @include themify() { + color: getThemifyVariable('primary-text-color'); + } } body, input, textarea, button { - font-family: Montserrat, sans-serif; + font-family: Montserrat, sans-serif; } .root-app, .app { - min-height: 100%; - height: 100vh; + min-height: 100%; + height: 100vh; } a { - @include themify() { - @extend %link; - } + @include themify() { + @extend %link; + } } input, button { - font-size: 1rem; + font-size: 1rem; } input, textarea { - padding: #{math.div(5, $base-font-size)}rem; - border: 1px solid; - border-radius: 2px; - padding: #{math.div(10, $base-font-size)}rem; - @include themify() { - color: getThemifyVariable("input-text-color"); - background-color: getThemifyVariable("input-background-color"); - border-color: getThemifyVariable("input-border-color"); - } + padding: #{math.div(5, $base-font-size)}rem; + border: 1px solid; + border-radius: 2px; + padding: #{math.div(10, $base-font-size)}rem; + @include themify() { + color: getThemifyVariable('input-text-color'); + background-color: getThemifyVariable('input-background-color'); + border-color: getThemifyVariable('input-border-color'); + } } input::selection, textarea::selection { - @include themify() { - color: getThemifyVariable("input-selection-text-color"); - background-color: getThemifyVariable("input-selection-background-color"); - } + @include themify() { + color: getThemifyVariable('input-selection-text-color'); + background-color: getThemifyVariable('input-selection-background-color'); + } } -button[type="submit"], -input[type="submit"] { - @include themify() { - @extend %button; - } +button[type='submit'], +input[type='submit'] { + @include themify() { + @extend %button; + } } -button[type="submit"]:disabled, -input[type="submit"]:disabled { - cursor: not-allowed; +button[type='submit']:disabled, +input[type='submit']:disabled { + cursor: not-allowed; } button { - @include themify() { - @extend %link; - } - background: transparent; - border: none; + @include themify() { + @extend %link; + } + background: transparent; + border: none; } h1 { - font-size: #{math.div(21, $base-font-size)}em; + font-size: #{math.div(21, $base-font-size)}em; } h2 { - font-size: #{math.div(21, $base-font-size)}em; + font-size: #{math.div(21, $base-font-size)}em; } h3 { - font-weight: normal; - font-size: #{math.div(16, $base-font-size)}rem; + font-weight: normal; + font-size: #{math.div(16, $base-font-size)}rem; } h4 { - font-weight: normal; + font-weight: normal; } h6 { - font-weight: normal; - font-size: #{math.div(12, $base-font-size)}rem; + font-weight: normal; + font-size: #{math.div(12, $base-font-size)}rem; } thead { - text-align: left; + text-align: left; } th { - text-align: left; + text-align: left; } a:focus, button:focus, input:focus, textarea:focus { - outline: none; - box-shadow: 0 0 0 1px $outline-color; + outline: none; + box-shadow: 0 0 0 1px $outline-color; } // screen reader only class // from https://www.scottohara.me/blog/2017/04/14/inclusively-hidden.html#hiding-content-visually .sr-only:not(:focus):not(:active) { - clip: rect(0 0 0 0); - clip-path: inset(50%); - height: 1px; - overflow: hidden; - position: absolute; - white-space: nowrap; - width: 1px; + clip: rect(0 0 0 0); + clip-path: inset(50%); + height: 1px; + overflow: hidden; + position: absolute; + white-space: nowrap; + width: 1px; } - // Donate banner custom properties body { - --donate-banner-dark: #c01c4c; - --donate-banner-background: url('https://foundation-donate-banner.netlify.app/p5.png'); -} \ No newline at end of file + --donate-banner-dark: #c01c4c; + --donate-banner-background: url('https://foundation-donate-banner.netlify.app/p5.png'); +} diff --git a/client/styles/base/_reset.scss b/client/styles/base/_reset.scss index 33cf3b3281..a6dcf5bf9b 100644 --- a/client/styles/base/_reset.scss +++ b/client/styles/base/_reset.scss @@ -1,21 +1,24 @@ // At some point, I will put in a ~real~ reset, but for now -html, body { - margin: 0; - padding: 0; - min-height: 100%; - height: 100%; +html, +body { + margin: 0; + padding: 0; + min-height: 100%; + height: 100%; } -ul, p { - padding: 0; - margin: 0; +ul, +p { + padding: 0; + margin: 0; } -h2, h3 { - margin: 0; +h2, +h3 { + margin: 0; } ul { list-style: none; -} \ No newline at end of file +} diff --git a/client/styles/components/_account.scss b/client/styles/components/_account.scss index 469be83497..2e7dfbfa52 100644 --- a/client/styles/components/_account.scss +++ b/client/styles/components/_account.scss @@ -1,4 +1,4 @@ -@use "sass:math"; +@use 'sass:math'; .account-settings__container { @include themify() { @@ -29,7 +29,6 @@ padding-bottom: #{math.div(15, $base-font-size)}rem; } - .account__social-stack { display: flex; @media (max-width: 770px) { @@ -37,7 +36,8 @@ align-items: center; gap: #{math.div(15, $base-font-size)}rem; - button, a { + button, + a { width: 100% !important; margin-right: 0; } diff --git a/client/styles/components/_api-key.scss b/client/styles/components/_api-key.scss index 7e4e2af471..1db17471c2 100644 --- a/client/styles/components/_api-key.scss +++ b/client/styles/components/_api-key.scss @@ -1,4 +1,4 @@ -@use "sass:math"; +@use 'sass:math'; .api-key-form__summary { padding-top: #{math.div(25, $base-font-size)}rem; @@ -48,32 +48,34 @@ } .api-key-list__delete-button { - width:#{math.div(20, $base-font-size)}rem; - height:#{math.div(20, $base-font-size)}rem; + width: #{math.div(20, $base-font-size)}rem; + height: #{math.div(20, $base-font-size)}rem; - text-align: center; + text-align: center; - @include themify() { - background-color: transparent; - border: none; - cursor: pointer; - padding: 0; - position: initial; - left: 0; - top: 0; - & g, & path { - opacity: 1; - fill: getThemifyVariable('icon-color'); - } + @include themify() { + background-color: transparent; + border: none; + cursor: pointer; + padding: 0; + position: initial; + left: 0; + top: 0; + & g, + & path { + opacity: 1; + fill: getThemifyVariable('icon-color'); } + } } .api-key-list__delete-button:hover { @include themify() { - & g, & path { - opacity: 1; - fill: getThemifyVariable('icon-hover-color'); - } + & g, + & path { + opacity: 1; + fill: getThemifyVariable('icon-hover-color'); + } } } diff --git a/client/styles/components/_asset-list.scss b/client/styles/components/_asset-list.scss index f359c1ae3b..8499d7fd57 100644 --- a/client/styles/components/_asset-list.scss +++ b/client/styles/components/_asset-list.scss @@ -1,4 +1,4 @@ -@use "sass:math"; +@use 'sass:math'; .asset-table-container { overflow-y: auto; @@ -8,7 +8,7 @@ .asset-table { width: 100%; - + max-height: 100%; border-spacing: 0; position: relative; @@ -27,7 +27,7 @@ } } -.asset-table thead th:nth-child(1){ +.asset-table thead th:nth-child(1) { padding-left: #{math.div(12, $base-font-size)}rem; } @@ -56,7 +56,7 @@ .asset-table thead { font-size: #{math.div(12, $base-font-size)}rem; @include themify() { - color: getThemifyVariable('inactive-text-color') + color: getThemifyVariable('inactive-text-color'); } } @@ -73,7 +73,7 @@ .asset-table__total { padding: 0 #{math.div(20, $base-font-size)}rem; position: sticky; - top: 0; + top: 0; @include themify() { background-color: getThemifyVariable('background-color'); } diff --git a/client/styles/components/_asset-size.scss b/client/styles/components/_asset-size.scss index d664415c37..c585b41902 100644 --- a/client/styles/components/_asset-size.scss +++ b/client/styles/components/_asset-size.scss @@ -1,4 +1,4 @@ -@use "sass:math"; +@use 'sass:math'; .asset-size { position: relative; diff --git a/client/styles/components/_banner.scss b/client/styles/components/_banner.scss index ae7eeb724e..7bde0da696 100644 --- a/client/styles/components/_banner.scss +++ b/client/styles/components/_banner.scss @@ -3,7 +3,7 @@ min-height: 2.2rem; text-align: center; padding: 1rem; - background-color: #DFED33; // yellow from p5.js website + background-color: #dfed33; // yellow from p5.js website border-bottom: 1px solid #000; a { @@ -23,10 +23,10 @@ .banner-close-button { display: flex; flex-direction: column; - align-items: center; + align-items: center; justify-content: center; height: 20px; - width:20px; + width: 20px; float: right; cursor: pointer; -} \ No newline at end of file +} diff --git a/client/styles/components/_collection-create.scss b/client/styles/components/_collection-create.scss index 94e0546df3..a7454c5145 100644 --- a/client/styles/components/_collection-create.scss +++ b/client/styles/components/_collection-create.scss @@ -1,4 +1,4 @@ -@use "sass:math"; +@use 'sass:math'; .collection-create { padding: #{math.div(24, $base-font-size)}rem; diff --git a/client/styles/components/_collection.scss b/client/styles/components/_collection.scss index bc5f9db5db..402eeb22e2 100644 --- a/client/styles/components/_collection.scss +++ b/client/styles/components/_collection.scss @@ -1,4 +1,4 @@ -@use "sass:math"; +@use 'sass:math'; .collection-container { padding: #{math.div(24, $base-font-size)}rem #{math.div(66, $base-font-size)}rem; @@ -6,9 +6,9 @@ flex: 1; overflow: hidden; display: flex; - flex-direction:column; + flex-direction: column; - @media (max-width:770px) { + @media (max-width: 770px) { padding: 0; } } @@ -28,7 +28,7 @@ .collection-metadata__columns { display: flex; - @media (max-width:770px) { + @media (max-width: 770px) { flex-direction: column; } } @@ -83,7 +83,9 @@ text-align: left; } -.collection-metadata__description .editable-input--has-value:not(:hover) .editable-input__label { +.collection-metadata__description + .editable-input--has-value:not(:hover) + .editable-input__label { @include themify() { color: getThemifyVariable('primary-text-color'); } @@ -132,9 +134,8 @@ min-height: 100%; } - // maybe don't need this? -[data-has-items=false] .collection-table-wrapper { +[data-has-items='false'] .collection-table-wrapper { display: flex; justify-content: center; align-items: center; @@ -152,8 +153,8 @@ .collection-row__remove-button { display: inline-block; - width:#{math.div(35, $base-font-size)}rem; - height:#{math.div(35, $base-font-size)}rem; + width: #{math.div(35, $base-font-size)}rem; + height: #{math.div(35, $base-font-size)}rem; @include icon(); @include themify() { // icon graphic @@ -167,8 +168,8 @@ } & svg { - width:#{math.div(35, $base-font-size)}rem; - height:#{math.div(35, $base-font-size)}rem; + width: #{math.div(35, $base-font-size)}rem; + height: #{math.div(35, $base-font-size)}rem; } &:hover, diff --git a/client/styles/components/_console-input.scss b/client/styles/components/_console-input.scss index ca0833c782..8eda2b33b5 100644 --- a/client/styles/components/_console-input.scss +++ b/client/styles/components/_console-input.scss @@ -1,4 +1,4 @@ -@use "sass:math"; +@use 'sass:math'; .console__input { width: 100%; @@ -13,12 +13,12 @@ width: auto; height: 38%; @include themify() { - & g, - & polygon, - & path { - fill: getThemifyVariable('secondary-text-color'); - } - } + & g, + & polygon, + & path { + fill: getThemifyVariable('secondary-text-color'); + } + } } .console-active__arrow-container { @@ -42,7 +42,7 @@ .console__editor .CodeMirror { border: none; - font-family: Inconsolata,monospace; + font-family: Inconsolata, monospace; @include themify() { background-color: getThemifyVariable('console-input-background-color'); } @@ -52,4 +52,4 @@ color: getThemifyVariable('console-color'); } } -} \ No newline at end of file +} diff --git a/client/styles/components/_console.scss b/client/styles/components/_console.scss index 4e17fe1cea..d174deaa9e 100644 --- a/client/styles/components/_console.scss +++ b/client/styles/components/_console.scss @@ -1,121 +1,121 @@ -@use "sass:math"; +@use 'sass:math'; .preview-console { - @include themify() { - background: getThemifyVariable('console-background-color'); - border-color: getThemifyVariable('ide-border-color'); - } - border-left: math.div(1, $base-font-size)rem solid; - border-right: math.div(1, $base-font-size)rem solid; - width: 100%; - height: 100%; - z-index: 1000; - display: flex; - flex-direction: column; + @include themify() { + background: getThemifyVariable('console-background-color'); + border-color: getThemifyVariable('ide-border-color'); + } + border-left: math.div(1, $base-font-size) rem solid; + border-right: math.div(1, $base-font-size) rem solid; + width: 100%; + height: 100%; + z-index: 1000; + display: flex; + flex-direction: column; - & > * { - position: relative; - text-align: left; - } + & > * { + position: relative; + text-align: left; + } } .preview-console__header { - @include themify() { - background-color: getThemifyVariable('console-header-background-color'); - color: getThemifyVariable('console-header-color'); - } - min-height: #{math.div(30, $base-font-size)}rem; - padding: #{math.div(5, $base-font-size)}rem; - display: flex; - justify-content: space-between; - align-items: center; + @include themify() { + background-color: getThemifyVariable('console-header-background-color'); + color: getThemifyVariable('console-header-color'); + } + min-height: #{math.div(30, $base-font-size)}rem; + padding: #{math.div(5, $base-font-size)}rem; + display: flex; + justify-content: space-between; + align-items: center; } .preview-console__header-title { - font-size: #{math.div(12, $base-font-size)}rem; - font-weight: normal; + font-size: #{math.div(12, $base-font-size)}rem; + font-weight: normal; } .preview-console__messages { - display: flex; - flex: 1; - flex-direction: column; - overflow-y: auto; - & div div div:first-child { - height: unset; + display: flex; + flex: 1; + flex-direction: column; + overflow-y: auto; + & div div div:first-child { + height: unset; line-height: unset; - font-size: unset; - } + font-size: unset; + } } .preview-console__collapse { - padding-top: #{math.div(3, $base-font-size)}rem; - @include icon(); - @include themify() { - & g, - & polygon, - & path { - fill: getThemifyVariable('secondary-text-color'); - } - &:hover { - & g, - & polygon, - & path { - fill: getThemifyVariable('logo-color'); - } - } - } - .preview-console--collapsed & { - display: none; - } + padding-top: #{math.div(3, $base-font-size)}rem; + @include icon(); + @include themify() { + & g, + & polygon, + & path { + fill: getThemifyVariable('secondary-text-color'); + } + &:hover { + & g, + & polygon, + & path { + fill: getThemifyVariable('logo-color'); + } + } + } + .preview-console--collapsed & { + display: none; + } } .preview-console__expand { - padding-top: #{math.div(3, $base-font-size)}rem; - @include icon(); - @include themify() { - & g, - & polygon, - & path { - fill: getThemifyVariable('secondary-text-color'); - } - &:hover { - & g, - & polygon, - & path { - fill: getThemifyVariable('logo-color'); - } - } - } - display: none; - .preview-console--collapsed & { - display: inline-block; - } + padding-top: #{math.div(3, $base-font-size)}rem; + @include icon(); + @include themify() { + & g, + & polygon, + & path { + fill: getThemifyVariable('secondary-text-color'); + } + &:hover { + & g, + & polygon, + & path { + fill: getThemifyVariable('logo-color'); + } + } + } + display: none; + .preview-console--collapsed & { + display: inline-block; + } } .preview-console__header-buttons { - display: flex; - align-items: center; + display: flex; + align-items: center; } .preview-console__clear { - @include themify() { - @extend %link; - color: getThemifyVariable('secondary-text-color'); - &:hover { - color: getThemifyVariable('logo-color'); - } - } - background: transparent; - border: none; - padding-right: #{math.div(10, $base-font-size)}rem; - .preview-console--collapsed & { - display: none; - } + @include themify() { + @extend %link; + color: getThemifyVariable('secondary-text-color'); + &:hover { + color: getThemifyVariable('logo-color'); + } + } + background: transparent; + border: none; + padding-right: #{math.div(10, $base-font-size)}rem; + .preview-console--collapsed & { + display: none; + } } .preview-console__body { - display: flex; - flex-direction: column; - height: calc(100% - #{math.div(30, $base-font-size)}rem); + display: flex; + flex-direction: column; + height: calc(100% - #{math.div(30, $base-font-size)}rem); } diff --git a/client/styles/components/_copyable-input.scss b/client/styles/components/_copyable-input.scss index 4db7690f9b..4d6cd2fd32 100644 --- a/client/styles/components/_copyable-input.scss +++ b/client/styles/components/_copyable-input.scss @@ -1,4 +1,4 @@ -@use "sass:math"; +@use 'sass:math'; .copyable-input__value-container { position: relative; @@ -22,8 +22,8 @@ } .copyable-input__label-container { - display: flex; - justify-content: space-between; + display: flex; + justify-content: space-between; } .copyable-input { @@ -45,8 +45,7 @@ } .tooltipped-n::before, -.tooltipped::before - { +.tooltipped::before { @include themify() { color: getThemifyVariable('button-background-hover-color'); border-top-color: getThemifyVariable('button-background-hover-color'); diff --git a/client/styles/components/_dashboard-header.scss b/client/styles/components/_dashboard-header.scss index 5d19b64cf0..88005b15bd 100644 --- a/client/styles/components/_dashboard-header.scss +++ b/client/styles/components/_dashboard-header.scss @@ -1,4 +1,4 @@ -@use "sass:math"; +@use 'sass:math'; .dashboard-header { padding: #{math.div(24, $base-font-size)}rem #{math.div(66, $base-font-size)}rem; @@ -14,7 +14,10 @@ .dashboard-header__nav { display: flex; flex-direction: column; - padding: #{math.div(10, $base-font-size)}rem #{math.div(16, $base-font-size)}rem; + padding: #{math.div(10, $base-font-size)}rem #{math.div( + 16, + $base-font-size + )}rem; gap: #{math.div(10, $base-font-size)}rem; .dashboard-header__tabs { @@ -26,11 +29,11 @@ font-size: #{math.div(15, $base-font-size)}rem; @include themify() { - color: getThemifyVariable("inactive-text-color"); + color: getThemifyVariable('inactive-text-color'); opacity: 0.7; &.dashboard-header__tab--selected { - color: getThemifyVariable("primary-text-color"); + color: getThemifyVariable('primary-text-color'); opacity: 1; } } @@ -79,13 +82,13 @@ width: 100%; @include themify() { - border-bottom: 1px solid getThemifyVariable("inactive-text-color"); + border-bottom: 1px solid getThemifyVariable('inactive-text-color'); } } .dashboard-header__tab { @include themify() { - color: getThemifyVariable("inactive-text-color"); + color: getThemifyVariable('inactive-text-color'); padding: 0; margin-right: #{math.div(26, $base-font-size)}rem; @media (max-width: 770px) { @@ -113,8 +116,8 @@ &:hover, &:focus, &.dashboard-header__tab--selected { - color: getThemifyVariable("primary-text-color"); - border-bottom-color: getThemifyVariable("nav-hover-color"); + color: getThemifyVariable('primary-text-color'); + border-bottom-color: getThemifyVariable('nav-hover-color'); cursor: pointer; } } diff --git a/client/styles/components/_editable-input.scss b/client/styles/components/_editable-input.scss index 2c6589d385..c3bb383add 100644 --- a/client/styles/components/_editable-input.scss +++ b/client/styles/components/_editable-input.scss @@ -1,4 +1,4 @@ -@use "sass:math"; +@use 'sass:math'; .editable-input { height: 70%; @@ -16,7 +16,7 @@ button.editable-input__label { fill: getThemifyVariable('inactive-text-color'); } &:hover { - color: getThemifyVariable('logo-color'); + color: getThemifyVariable('logo-color'); & path { fill: getThemifyVariable('logo-color'); } diff --git a/client/styles/components/_editor.scss b/client/styles/components/_editor.scss index 0aab1d4b9f..35d316778f 100644 --- a/client/styles/components/_editor.scss +++ b/client/styles/components/_editor.scss @@ -1,4 +1,4 @@ -@use "sass:math"; +@use 'sass:math'; .CodeMirror { font-family: Inconsolata, monospace; @@ -13,7 +13,7 @@ width: #{math.div(32, $base-font-size)}rem; left: #{math.div(-3, $base-font-size)}rem !important; @include themify() { - color: getThemifyVariable("inactive-text-color"); + color: getThemifyVariable('inactive-text-color'); } } @@ -65,10 +65,10 @@ pre.CodeMirror-line { .CodeMirror-lint-tooltip { @include themify() { - background-color: getThemifyVariable("modal-background-color"); - border: 1px solid getThemifyVariable("modal-border-color"); - box-shadow: 0 12px 12px getThemifyVariable("shadow-color"); - color: getThemifyVariable("primary-text-color"); + background-color: getThemifyVariable('modal-background-color'); + border: 1px solid getThemifyVariable('modal-border-color'); + box-shadow: 0 12px 12px getThemifyVariable('shadow-color'); + color: getThemifyVariable('primary-text-color'); } border-radius: 2px; font-family: Montserrat, sans-serif; @@ -76,8 +76,8 @@ pre.CodeMirror-line { .CodeMirror-gutters { @include themify() { - background-color: getThemifyVariable("editor-gutter-color"); - border-color: getThemifyVariable("ide-border-color"); + background-color: getThemifyVariable('editor-gutter-color'); + border-color: getThemifyVariable('ide-border-color'); } // left: 0 !important; width: #{math.div(48, $base-font-size)}rem; @@ -92,7 +92,7 @@ pre.CodeMirror-line { top: 0; left: 50%; margin-left: #{math.div(-552 * 0.5, $base-font-size)}rem; - + @media (max-width: 770px) { left: 0; right: 0; @@ -105,14 +105,15 @@ pre.CodeMirror-line { width: 580px; font-family: Montserrat, sans-serif; - padding: #{math.div(8, $base-font-size)}rem #{math.div(10, $base-font-size)}rem #{math.div(5, $base-font-size)}rem #{math.div(9, $base-font-size)}rem; + padding: #{math.div(8, $base-font-size)}rem #{math.div(10, $base-font-size)}rem + #{math.div(5, $base-font-size)}rem #{math.div(9, $base-font-size)}rem; border-radius: 2px; @include themify() { - background-color: getThemifyVariable("modal-background-color"); - box-shadow: 0 12px 12px 0 getThemifyVariable("shadow-color"); - border: solid 0.5px getThemifyVariable("modal-border-color"); + background-color: getThemifyVariable('modal-background-color'); + box-shadow: 0 12px 12px 0 getThemifyVariable('shadow-color'); + border: solid 0.5px getThemifyVariable('modal-border-color'); } } @@ -191,11 +192,11 @@ pre.CodeMirror-line { max-width: #{math.div(166, $base-font-size)}rem; margin-bottom: #{math.div(4, $base-font-size)}rem; @include themify() { - color: getThemifyVariable("input-text-color"); - background-color: getThemifyVariable("input-secondary-background-color"); - border: solid 0.5px getThemifyVariable("button-border-color"); + color: getThemifyVariable('input-text-color'); + background-color: getThemifyVariable('input-secondary-background-color'); + border: solid 0.5px getThemifyVariable('button-border-color'); &::placeholder { - color: getThemifyVariable("inactive-text-color"); + color: getThemifyVariable('inactive-text-color'); } } } @@ -235,7 +236,7 @@ pre.CodeMirror-line { padding: #{math.div(2, $base-font-size)}rem #{math.div(7, $base-font-size)}rem; border: 2px solid transparent; &:hover { - border-color: getThemifyVariable("button-border-color"); + border-color: getThemifyVariable('button-border-color'); } } width: #{math.div(35, $base-font-size)}rem; @@ -255,11 +256,11 @@ pre.CodeMirror-line { @extend %hidden-element; } -[aria-checked="true"] { +[aria-checked='true'] { @include themify() { - color: getThemifyVariable("heavy-text-color"); - background-color: getThemifyVariable("button-secondary-background-color"); - border-color: getThemifyVariable("button-border-color"); + color: getThemifyVariable('heavy-text-color'); + background-color: getThemifyVariable('button-secondary-background-color'); + border-color: getThemifyVariable('button-border-color'); } } @@ -294,11 +295,7 @@ pre.CodeMirror-line { // foldgutter .CodeMirror-foldmarker { - text-shadow: - -1px 0 #ed225d, - 0 1px #ed225d, - 1px 0 #ed225d, - 0 -1px #ed225d; + text-shadow: -1px 0 #ed225d, 0 1px #ed225d, 1px 0 #ed225d, 0 -1px #ed225d; color: #fff; /* background-color: rgba(237, 34, 93, 0.42); */ /* border-radius: 3px; */ @@ -319,10 +316,10 @@ pre.CodeMirror-line { line-height: 1; } .CodeMirror-foldgutter-open:after { - content: "\25BE"; + content: '\25BE'; } .CodeMirror-foldgutter-folded:after { - content: "\25B8"; + content: '\25B8'; } .CodeMirror-foldgutter-open, @@ -333,20 +330,20 @@ pre.CodeMirror-line { .CodeMirror-foldgutter-open:after { @include themify() { - background-image: getThemifyVariable("codefold-icon-open"); + background-image: getThemifyVariable('codefold-icon-open'); } } .CodeMirror-foldgutter-folded:after { @include themify() { - background-image: getThemifyVariable("codefold-icon-closed"); + background-image: getThemifyVariable('codefold-icon-closed'); } } .CodeMirror-foldgutter-folded:after, .CodeMirror-foldgutter-open:after { background-size: 10px 10px; - content: ""; + content: ''; padding-left: 15px; background-repeat: no-repeat; background-position: center center; @@ -380,7 +377,7 @@ pre.CodeMirror-line { width: 100%; position: absolute; @include themify() { - border: 1px solid getThemifyVariable("ide-border-color"); + border: 1px solid getThemifyVariable('ide-border-color'); } &.editor-holder--hidden .CodeMirror { display: none; @@ -393,7 +390,7 @@ pre.CodeMirror-line { .editor__file-name { @include themify() { - color: getThemifyVariable("primary-text-color"); + color: getThemifyVariable('primary-text-color'); } height: #{math.div(29, $base-font-size)}rem; padding-top: #{math.div(7, $base-font-size)}rem; @@ -406,7 +403,7 @@ pre.CodeMirror-line { .editor__library-version { @include themify() { - color: getThemifyVariable("primary-text-color"); + color: getThemifyVariable('primary-text-color'); } position: absolute; top: 0; @@ -427,7 +424,7 @@ pre.CodeMirror-line { @extend %modal; position: absolute; @include themify() { - background: getThemifyVariable("background-color"); + background: getThemifyVariable('background-color'); } & .CodeMirror-lines { padding: 0; diff --git a/client/styles/components/_error-modal.scss b/client/styles/components/_error-modal.scss index c834b68c2a..d2c94ba0fa 100644 --- a/client/styles/components/_error-modal.scss +++ b/client/styles/components/_error-modal.scss @@ -1,4 +1,4 @@ -@use "sass:math"; +@use 'sass:math'; .error-modal { @extend %modal; diff --git a/client/styles/components/_feedback.scss b/client/styles/components/_feedback.scss index 47039b1dba..4769f9b494 100644 --- a/client/styles/components/_feedback.scss +++ b/client/styles/components/_feedback.scss @@ -1,4 +1,4 @@ -@use "sass:math"; +@use 'sass:math'; .feedback__content { display: flex; @@ -36,4 +36,4 @@ @include themify() { fill: getThemifyVariable('primary-text-color'); } -} \ No newline at end of file +} diff --git a/client/styles/components/_form-container.scss b/client/styles/components/_form-container.scss index 0c48b7070b..238249f90a 100644 --- a/client/styles/components/_form-container.scss +++ b/client/styles/components/_form-container.scss @@ -1,84 +1,84 @@ -@use "sass:math"; +@use 'sass:math'; .form-container { - text-align: center; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - flex: 1; + text-align: center; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + flex: 1; - @media (max-width: 550px) { - text-align: left; - justify-content: start; - } + @media (max-width: 550px) { + text-align: left; + justify-content: start; + } } .form-container--align-left { - text-align: left; + text-align: left; } .form-container--align-top { - height: unset; + height: unset; } .form-container__header { - width: 100%; - padding: #{math.div(15, $base-font-size)}rem #{math.div(34, $base-font-size)}rem; - display: flex; - justify-content: space-between; + width: 100%; + padding: #{math.div(15, $base-font-size)}rem #{math.div(34, $base-font-size)}rem; + display: flex; + justify-content: space-between; } .form-container__content { - height: 100%; - max-width: 90vw; - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; - margin-bottom: 20px; + height: 100%; + max-width: 90vw; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + margin-bottom: 20px; } .form-container--align-left .form-container__content { - align-items: left; + align-items: left; } .form-container__title { - font-weight: normal; - @include themify() { - color: getThemifyVariable("form-title-color"); - } + font-weight: normal; + @include themify() { + color: getThemifyVariable('form-title-color'); + } - @media (max-width: 770px) { - display: none; - } + @media (max-width: 770px) { + display: none; + } } .form-container__context { - @include themify() { - color: getThemifyVariable("secondary-text-color"); - } + @include themify() { + color: getThemifyVariable('secondary-text-color'); + } } .form-container__divider { - padding: #{math.div(20, $base-font-size)}rem 0; + padding: #{math.div(20, $base-font-size)}rem 0; - @media (max-width: 770px) { - text-align: center; - } + @media (max-width: 770px) { + text-align: center; + } } .form-container__logo-button { - @include icon(); + @include icon(); } .form-container__exit-button { - @include icon(); + @include icon(); } .form-container__stack > * + * { - margin-top: #{math.div(10, $base-font-size)}rem; + margin-top: #{math.div(10, $base-font-size)}rem; } .form__navigation-options a { - font-weight: bold; - } + font-weight: bold; +} diff --git a/client/styles/components/_forms.scss b/client/styles/components/_forms.scss index 7520eae77d..5e7f5906fd 100644 --- a/client/styles/components/_forms.scss +++ b/client/styles/components/_forms.scss @@ -1,4 +1,4 @@ -@use "sass:math"; +@use 'sass:math'; .form-error { display: block; @@ -7,7 +7,7 @@ font-size: #{math.div(12, $base-font-size)}rem; text-align: left; @include themify() { - color: getThemifyVariable("error-color"); + color: getThemifyVariable('error-color'); } } @@ -29,7 +29,7 @@ margin-top: #{math.div(16, $base-font-size)}rem; font-size: #{math.div(12, $base-font-size)}rem; @include themify() { - color: getThemifyVariable("form-navigation-options-color"); + color: getThemifyVariable('form-navigation-options-color'); } @media (max-width: 550px) { @@ -49,7 +49,7 @@ margin-bottom: #{math.div(7, $base-font-size)}rem; display: block; @include themify() { - color: getThemifyVariable("form-secondary-title-color"); + color: getThemifyVariable('form-secondary-title-color'); } } @@ -63,10 +63,10 @@ height: #{math.div(40, $base-font-size)}rem; font-size: #{math.div(16, $base-font-size)}rem; @include themify() { - color: getThemifyVariable("form-input-text-color"); - background-color: getThemifyVariable("input-background-color"); + color: getThemifyVariable('form-input-text-color'); + background-color: getThemifyVariable('input-background-color'); } - + @media (max-width: 770px) { max-width: 100%; width: 100%; @@ -83,13 +83,12 @@ font-size: #{math.div(30, $base-font-size)}rem; position: absolute; right: 0px; - + & svg { transform: translateY(10%); } } - .form__input[type='password']::-ms-reveal { display: none; } @@ -101,7 +100,7 @@ .form__input::placeholder { @include themify() { - color: getThemifyVariable("form-input-placeholder-text-color"); + color: getThemifyVariable('form-input-placeholder-text-color'); } } @@ -115,11 +114,11 @@ .form__status { @include themify() { - color: getThemifyVariable("form-navigation-options-color"); + color: getThemifyVariable('form-navigation-options-color'); } } -.form [type="submit"] { +.form [type='submit'] { margin-left: auto; margin-right: auto; } diff --git a/client/styles/components/_hints.scss b/client/styles/components/_hints.scss index 7084b460e7..5dc2ead78c 100644 --- a/client/styles/components/_hints.scss +++ b/client/styles/components/_hints.scss @@ -1,4 +1,4 @@ -@use "sass:math"; +@use 'sass:math'; .CodeMirror-hints { position: absolute; @@ -10,7 +10,7 @@ padding: 0; box-shadow: 0 0 #{math.div(18, $base-font-size)}rem 0 rgba(0, 0, 0, 0.16); - border: #{math.div(1, $base-font-size)}rem solid #A6A6A6; + border: #{math.div(1, $base-font-size)}rem solid #a6a6a6; font-size: 100%; font-family: Inconsolata, monospace; @@ -26,7 +26,8 @@ .CodeMirror-hint { color: getThemifyVariable('hint-text-color'); - border-bottom: #{math.div(1, $base-font-size)}rem solid getThemifyVariable('hint-item-border-bottom-color'); + border-bottom: #{math.div(1, $base-font-size)}rem solid + getThemifyVariable('hint-item-border-bottom-color'); } .hint-container { @@ -98,34 +99,39 @@ width: calc(100% - 1rem); // Match padding box-sizing: border-box; } - - .fun-name, .obj-name { + + .fun-name, + .obj-name { color: getThemifyVariable('hint-fun-text-color'); } - - .var-name, .boolean-name { + + .var-name, + .boolean-name { color: getThemifyVariable('hint-var-text-color'); } .keyword-name { color: getThemifyVariable('hint-keyword-text-color'); } - + .hint-type { color: getThemifyVariable('hint-type-text-color'); margin-right: #{math.div(10, $base-font-size)}rem; } - + a { color: getThemifyVariable('hint-arrow-color'); background: getThemifyVariable('hint-arrow-background-color'); - &:hover, &:active, &.focused-hint-link { + &:hover, + &:active, + &.focused-hint-link { background: getThemifyVariable('hint-arrow-background-active-color'); } &.focused-hint-link { - outline: #{math.div(3, $base-font-size)}rem solid getThemifyVariable('hint-arrow-focus-outline-color'); + outline: #{math.div(3, $base-font-size)}rem solid + getThemifyVariable('hint-arrow-focus-outline-color'); outline-offset: #{math.div(-3, $base-font-size)}rem; } } @@ -134,7 +140,7 @@ background: getThemifyVariable('hint-no-link-background-color'); pointer-events: none; } - + li.CodeMirror-hint-active:not(.unfocused) { background: getThemifyVariable('hint-item-active-background-color'); outline: getThemifyVariable('hint-item-active-outline'); @@ -152,23 +158,26 @@ color: getThemifyVariable('hint-item-active-text-color'); } - .fun-name, .obj-name { + .fun-name, + .obj-name { background-color: getThemifyVariable('hint-fun-text-color'); } - - .var-name, .boolean-name { + + .var-name, + .boolean-name { background-color: getThemifyVariable('hint-var-text-color'); } .keyword-name { background-color: getThemifyVariable('hint-keyword-text-color'); } - - .hint-type, .plain-hint-item { + + .hint-type, + .plain-hint-item { color: getThemifyVariable('hint-item-active-type-text-color'); } } - + .CodeMirror-hint:hover:not(.CodeMirror-hint-active) { background: getThemifyVariable('hint-item-hover-background-color'); } @@ -190,7 +199,8 @@ z-index: 999; } - &:only-child, &:last-child { + &:only-child, + &:last-child { border-bottom: none !important; } @@ -199,8 +209,9 @@ width: 100%; height: 100%; } - - .hint-name, .plain-hint-item { + + .hint-name, + .plain-hint-item { display: flex; align-items: center; padding: 0 0.5rem; @@ -209,7 +220,7 @@ line-height: 100%; font-weight: bold; } - + .hint-type { margin: 0.5rem 2.4rem 0.5rem auto; font-size: 1rem; @@ -220,8 +231,9 @@ .hint-hidden { @extend %hidden-element; } - - a, .no-link-placeholder { + + a, + .no-link-placeholder { // position: absolute; top: 0; right: 0; @@ -235,8 +247,9 @@ outline: none; z-index: 1; } - - a:focus, a:active { + + a:focus, + a:active { outline: 0; } } @@ -272,5 +285,7 @@ } @keyframes inline-hint-caret-blink { - 50% { border-color: transparent; } + 50% { + border-color: transparent; + } } diff --git a/client/styles/components/_keyboard-shortcuts.scss b/client/styles/components/_keyboard-shortcuts.scss index ce0f4a344a..b1aa0e6829 100644 --- a/client/styles/components/_keyboard-shortcuts.scss +++ b/client/styles/components/_keyboard-shortcuts.scss @@ -1,4 +1,4 @@ -@use "sass:math"; +@use 'sass:math'; .keyboard-shortcuts { padding: #{math.div(20, $base-font-size)}rem; @@ -28,7 +28,7 @@ padding: #{math.div(3, $base-font-size)}rem; min-inline-size: max-content; @include themify { - border: 1px solid getThemifyVariable("button-border-color"); + border: 1px solid getThemifyVariable('button-border-color'); border-radius: 3px; } } @@ -47,7 +47,7 @@ .keyboard-shortcuts__title:not(:first-of-type) { @include themify() { - border-top: 1px dashed getThemifyVariable("button-border-color"); + border-top: 1px dashed getThemifyVariable('button-border-color'); padding-top: #{math.div(10, $base-font-size)}rem; } } diff --git a/client/styles/components/_modal.scss b/client/styles/components/_modal.scss index 9942b9887e..31ba6f1d99 100644 --- a/client/styles/components/_modal.scss +++ b/client/styles/components/_modal.scss @@ -1,4 +1,4 @@ -@use "sass:math"; +@use 'sass:math'; .modal { position: absolute; @@ -38,15 +38,18 @@ margin-bottom: #{math.div(20, $base-font-size)}rem; } -.new-folder-form__input-wrapper, .new-file-form__input-wrapper { +.new-folder-form__input-wrapper, +.new-file-form__input-wrapper { display: flex; } -.new-file-form__name-label, .new-folder-form__name-label { +.new-file-form__name-label, +.new-folder-form__name-label { @extend %hidden-element; } -.new-file-form__name-input, .new-folder-form__name-input { +.new-file-form__name-input, +.new-folder-form__name-input { margin-right: #{math.div(10, $base-font-size)}rem; flex: 1; } diff --git a/client/styles/components/_nav.scss b/client/styles/components/_nav.scss index 5d597596ac..b0eacdb70f 100644 --- a/client/styles/components/_nav.scss +++ b/client/styles/components/_nav.scss @@ -1,4 +1,4 @@ -@use "sass:math"; +@use 'sass:math'; .nav { height: #{math.div(42, $base-font-size)}rem; @@ -27,7 +27,7 @@ .nav__menubar { display: flex; flex-direction: row; - width:100%; + width: 100%; justify-content: space-between; } @@ -57,11 +57,11 @@ } // base focus styles -.nav__item button:focus { +.nav__item button:focus { @include themify() { background-color: getThemifyVariable('nav-hover-color'); } - + .nav__item-header { @include themify() { color: getThemifyVariable('button-hover-color'); @@ -73,10 +73,9 @@ @include themify() { fill: getThemifyVariable('button-hover-color'); } - } + } } - .nav__dropdown-item { & button:focus, & a:focus { @@ -131,8 +130,9 @@ color: getThemifyVariable('button-hover-color'); } } - - & g, & path { + + & g, + & path { @include themify() { fill: getThemifyVariable('nav-hover-color'); } @@ -150,7 +150,8 @@ @include themify() { color: getThemifyVariable('nav-hover-color'); } - & g, & path { + & g, + & path { @include themify() { fill: getThemifyVariable('nav-hover-color'); } @@ -158,17 +159,17 @@ } .nav__item-header-triangle { - margin-left: #{math.div(5, $base-font-size)}rem; + margin-left: #{math.div(5, $base-font-size)}rem; } .nav__dropdown { @include themify() { - color: getThemifyVariable('nav-hover-color'); - } + color: getThemifyVariable('nav-hover-color'); + } } .nav__item-header-triangle { - margin-left: #{math.div(5, $base-font-size)}rem; + margin-left: #{math.div(5, $base-font-size)}rem; } .nav__dropdown { @@ -232,24 +233,19 @@ } .svg__logo { - @include themify() { // Set background color of the logo background-color: getThemifyVariable('logo-color'); } - } -.svg__logo g path{ - +.svg__logo g path { @include themify() { // Set internal color of the logo; fill: getThemifyVariable('logo-background-color'); } - } - .nav__keyboard-shortcut { font-size: #{math.div(12, $base-font-size)}rem; font-family: Inconsololata, monospace; @@ -266,7 +262,8 @@ } .nav__back-icon { - & g, & path { + & g, + & path { opacity: 1; @include themify() { fill: getThemifyVariable('inactive-text-color'); diff --git a/client/styles/components/_new-password.scss b/client/styles/components/_new-password.scss index 735e0ff76d..e15865567f 100644 --- a/client/styles/components/_new-password.scss +++ b/client/styles/components/_new-password.scss @@ -1,4 +1,4 @@ -@use "sass:math"; +@use 'sass:math'; .new-password-form { .new-password--invalid & { diff --git a/client/styles/components/_overlay.scss b/client/styles/components/_overlay.scss index 8cacda4b4f..de457c1f08 100644 --- a/client/styles/components/_overlay.scss +++ b/client/styles/components/_overlay.scss @@ -1,4 +1,4 @@ -@use "sass:math"; +@use 'sass:math'; .overlay { position: fixed; @@ -37,7 +37,7 @@ } } -.overlay__body:has(.collection-create){ +.overlay__body:has(.collection-create) { max-height: none; } diff --git a/client/styles/components/_p5-contrast-codemirror-theme.scss b/client/styles/components/_p5-contrast-codemirror-theme.scss index 93c604d0cc..d07806d9a6 100644 --- a/client/styles/components/_p5-contrast-codemirror-theme.scss +++ b/client/styles/components/_p5-contrast-codemirror-theme.scss @@ -10,21 +10,21 @@ //light gray: #f4f4f4 //dark gray: #b5b5b5 -@use "sass:math"; +@use 'sass:math'; -$p5-contrast-black: #1C1C1C; -$p5-contrast-gray: #A0A0A0; -$p5-contrast-white: #FDFDFD; +$p5-contrast-black: #1c1c1c; +$p5-contrast-gray: #a0a0a0; +$p5-contrast-white: #fdfdfd; $p5-contrast-darkgray: #333333; -$p5-contrast-lightgray: #C1C1C1; -$p5-contrast-blue: #00FFFF; -$p5-contrast-green: #2DE9B6; -$p5-contrast-yellow: #F5DC23; -$p5-contrast-orange: #FFA95D; -$p5-contrast-pink: #FFA9D9; +$p5-contrast-lightgray: #c1c1c1; +$p5-contrast-blue: #00ffff; +$p5-contrast-green: #2de9b6; +$p5-contrast-yellow: #f5dc23; +$p5-contrast-orange: #ffa95d; +$p5-contrast-pink: #ffa9d9; $p5-contrast-gutter: #454545; -$p5-contrast-number: #FDFDFD; +$p5-contrast-number: #fdfdfd; $p5-contrast-selected: $middle-dark; $p5-contrast-activeline: #999999; @@ -82,10 +82,22 @@ $p5-contrast-activeline: #999999; } .cm-s-p5-contrast { - .CodeMirror-selected { background: $p5-contrast-selected; } - .CodeMirror-focused .CodeMirror-selected { background: $p5-contrast-selected; } - .CodeMirror-line::selection, .CodeMirror-line > span::selection, .CodeMirror-line > span > span::selection { background: $p5-contrast-selected; } - .CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection { background: $p5-contrast-selected; } + .CodeMirror-selected { + background: $p5-contrast-selected; + } + .CodeMirror-focused .CodeMirror-selected { + background: $p5-contrast-selected; + } + .CodeMirror-line::selection, + .CodeMirror-line > span::selection, + .CodeMirror-line > span > span::selection { + background: $p5-contrast-selected; + } + .CodeMirror-line::-moz-selection, + .CodeMirror-line > span::-moz-selection, + .CodeMirror-line > span > span::-moz-selection { + background: $p5-contrast-selected; + } } .cm-s-p5-contrast .CodeMirror-activeline-background { diff --git a/client/styles/components/_p5-dark-codemirror-theme.scss b/client/styles/components/_p5-dark-codemirror-theme.scss index 77940fa188..2115519b22 100644 --- a/client/styles/components/_p5-dark-codemirror-theme.scss +++ b/client/styles/components/_p5-dark-codemirror-theme.scss @@ -10,16 +10,16 @@ //light gray: #f4f4f4 //dark gray: #b5b5b5 -$p5-dark-lightbrown: #A67F59; -$p5-light-green: #42F48F; -$p5-dark-black: #1C1C1C; -$p5-dark-pink: #DE4A9B; -$p5-dark-gray: #9B9B9B; -$p5-dark-lightblue: #0F9DD7; +$p5-dark-lightbrown: #a67f59; +$p5-light-green: #42f48f; +$p5-dark-black: #1c1c1c; +$p5-dark-pink: #de4a9b; +$p5-dark-gray: #9b9b9b; +$p5-dark-lightblue: #0f9dd7; $p5-dark-darkblue: #318094; -$p5-dark-white: #FDFDFD; -$p5-dark-orange: #EE9900; -$p5-dark-lightgray: #E0D7D1; +$p5-dark-white: #fdfdfd; +$p5-dark-orange: #ee9900; +$p5-dark-lightgray: #e0d7d1; $p5-dark-darkgray: #666666; $p5-dark-green: #58a10b; $p5-dark-goldbrown: #b58318; @@ -85,10 +85,22 @@ $p5-dark-error: #df3a3d; } .cm-s-p5-dark { - .CodeMirror-selected { background: $p5-dark-selected; } - .CodeMirror-focused .CodeMirror-selected { background: $p5-dark-selected; } - .CodeMirror-line::selection, .CodeMirror-line > span::selection, .CodeMirror-line > span > span::selection { background: $p5-dark-selected; } - .CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection { background: $p5-dark-selected; } + .CodeMirror-selected { + background: $p5-dark-selected; + } + .CodeMirror-focused .CodeMirror-selected { + background: $p5-dark-selected; + } + .CodeMirror-line::selection, + .CodeMirror-line > span::selection, + .CodeMirror-line > span > span::selection { + background: $p5-dark-selected; + } + .CodeMirror-line::-moz-selection, + .CodeMirror-line > span::-moz-selection, + .CodeMirror-line > span > span::-moz-selection { + background: $p5-dark-selected; + } } .cm-s-p5-dark .CodeMirror-activeline-background { diff --git a/client/styles/components/_p5-light-codemirror-theme.scss b/client/styles/components/_p5-light-codemirror-theme.scss index c2e8062865..767192f445 100644 --- a/client/styles/components/_p5-light-codemirror-theme.scss +++ b/client/styles/components/_p5-light-codemirror-theme.scss @@ -10,16 +10,15 @@ //light gray: #f4f4f4 //dark gray: #b5b5b5 -$p5-light-brown: #7A5A3A; +$p5-light-brown: #7a5a3a; $p5-light-black: #333333; -$p5-light-pink: #D52889; +$p5-light-pink: #d52889; $p5-light-gray: #666; -$p5-light-blue: #0B7CA9; +$p5-light-blue: #0b7ca9; $p5-light-white: $lighter; -$p5-light-orange: #A06801; +$p5-light-orange: #a06801; $p5-light-lightgray: $middle-gray; -$p5-light-green: #47820A; - +$p5-light-green: #47820a; $p5-light-gutter: #f4f4f4; $p5-light-number: #b5b5b5; @@ -80,10 +79,22 @@ $p5-light-activeline: rgb(207, 207, 207); } .cm-s-p5-light { - .CodeMirror-selected { background: $p5-light-selected; } - .CodeMirror-focused .CodeMirror-selected { background: $p5-light-selected; } - .CodeMirror-line::selection, .CodeMirror-line > span::selection, .CodeMirror-line > span > span::selection { background: $p5-light-selected; } - .CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection { background: $p5-light-selected; } + .CodeMirror-selected { + background: $p5-light-selected; + } + .CodeMirror-focused .CodeMirror-selected { + background: $p5-light-selected; + } + .CodeMirror-line::selection, + .CodeMirror-line > span::selection, + .CodeMirror-line > span > span::selection { + background: $p5-light-selected; + } + .CodeMirror-line::-moz-selection, + .CodeMirror-line > span::-moz-selection, + .CodeMirror-line > span > span::-moz-selection { + background: $p5-light-selected; + } } .cm-s-p5-light .CodeMirror-activeline-background { diff --git a/client/styles/components/_preferences.scss b/client/styles/components/_preferences.scss index e0830f3543..45bc215d7c 100644 --- a/client/styles/components/_preferences.scss +++ b/client/styles/components/_preferences.scss @@ -1,4 +1,4 @@ -@use "sass:math"; +@use 'sass:math'; .preferences { width: 100%; @@ -6,7 +6,8 @@ max-width: 100%; max-height: 100%; z-index: 9999; - padding: 0 #{math.div(20, $base-font-size)}rem #{math.div(2, $base-font-size)}rem #{math.div(20, $base-font-size)}rem; + padding: 0 #{math.div(20, $base-font-size)}rem #{math.div(2, $base-font-size)}rem + #{math.div(20, $base-font-size)}rem; display: flex; flex-direction: column; outline: none; @@ -46,7 +47,7 @@ padding-bottom: #{math.div(12, $base-font-size)}rem; & + & { @include themify() { - border-top: 1px dashed getThemifyVariable("button-border-color"); + border-top: 1px dashed getThemifyVariable('button-border-color'); } } } @@ -60,7 +61,7 @@ .preference__subtitle { @include themify() { - color: getThemifyVariable("inactive-text-color"); + color: getThemifyVariable('inactive-text-color'); } width: 100%; margin-bottom: #{math.div(10, $base-font-size)}rem; @@ -91,9 +92,9 @@ .preference__value { @include themify() { border: #{math.div(1, $base-font-size)}rem solid - getThemifyVariable("button-border-color"); + getThemifyVariable('button-border-color'); // background-color: getThemifyVariable("button-background-color"); - color: getThemifyVariable("input-text-color"); + color: getThemifyVariable('input-text-color'); background-color: getThemifyVariable('input-background-color'); } text-align: center; @@ -109,12 +110,15 @@ .preference__label { @include themify() { - color: getThemifyVariable("secondary-text-color"); + color: getThemifyVariable('secondary-text-color'); &:hover { - color: getThemifyVariable("heavy-text-color"); + color: getThemifyVariable('heavy-text-color'); } } - margin: #{math.div(-15, $base-font-size)}rem 0 0 #{math.div(-5, $base-font-size)}rem; + margin: #{math.div(-15, $base-font-size)}rem 0 0 #{math.div( + -5, + $base-font-size + )}rem; font-size: #{math.div(9, $base-font-size)}rem; width: #{math.div(44, $base-font-size)}rem; } @@ -122,13 +126,13 @@ .react-tabs__tab--selected { @include themify() { border-bottom: #{math.div(4, $base-font-size)}rem solid - getThemifyVariable("button-background-hover-color"); + getThemifyVariable('button-background-hover-color'); } } .react-tabs__tab--selected .preference__subheading { @include themify() { - color: getThemifyVariable("primary-text-color"); + color: getThemifyVariable('primary-text-color'); } } @@ -144,7 +148,7 @@ &:hover { @include themify() { border-bottom: #{math.div(4, $base-font-size)}rem solid - getThemifyVariable("button-background-hover-color"); + getThemifyVariable('button-background-hover-color'); } } } @@ -167,8 +171,8 @@ @extend %hidden-element; } -input[type="number"]::-webkit-inner-spin-button, -input[type="number"]::-webkit-outer-spin-button { +input[type='number']::-webkit-inner-spin-button, +input[type='number']::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; } @@ -191,7 +195,7 @@ input[type="number"]::-webkit-outer-spin-button { @include themify() { @extend %preference-option; &:hover { - color: getThemifyVariable("button-background-hover-color"); + color: getThemifyVariable('button-background-hover-color'); } } margin-left: #{math.div(30, $base-font-size)}rem; @@ -208,13 +212,13 @@ input[type="number"]::-webkit-outer-spin-button { .preference__radio-button:checked + .preference__option { @include themify() { //for some reason this won't work for getThemifyVariable - color: map-get($theme-map, "heavy-text-color"); + color: map-get($theme-map, 'heavy-text-color'); font-weight: bold; } } .preference__radio-button:focus + .preference__option, .preference__radio-button:focus-visible + .preference__option { - outline: 2px solid $dodgerblue; + outline: 2px solid $dodgerblue; outline-offset: 2px; border-radius: 4px; } @@ -226,4 +230,3 @@ input[type="number"]::-webkit-outer-spin-button { .preference__option.preference__canvas:not(:last-child) { padding-right: #{math.div(14, $base-font-size)}rem; } - diff --git a/client/styles/components/_preview-frame.scss b/client/styles/components/_preview-frame.scss index 81d497bb05..46335f9bdb 100644 --- a/client/styles/components/_preview-frame.scss +++ b/client/styles/components/_preview-frame.scss @@ -1,4 +1,4 @@ -@use "sass:math"; +@use 'sass:math'; .preview-frame-holder { display: flex; diff --git a/client/styles/components/_preview-nav.scss b/client/styles/components/_preview-nav.scss index 82cb626cc5..c8570bf48d 100644 --- a/client/styles/components/_preview-nav.scss +++ b/client/styles/components/_preview-nav.scss @@ -1,11 +1,11 @@ -@use "sass:math"; +@use 'sass:math'; .preview-nav__editor-svg { & svg { width: #{math.div(22, $base-font-size)}rem; height: #{math.div(22, $base-font-size)}rem; @include themify() { - fill: getThemifyVariable('button-nav-inactive-color'); + fill: getThemifyVariable('button-nav-inactive-color'); } &:hover { @include themify() { diff --git a/client/styles/components/_quick-add.scss b/client/styles/components/_quick-add.scss index 96106c5d02..3df4ee4eb3 100644 --- a/client/styles/components/_quick-add.scss +++ b/client/styles/components/_quick-add.scss @@ -1,4 +1,4 @@ -@use "sass:math"; +@use 'sass:math'; .quick-add { width: auto; @@ -15,7 +15,8 @@ height: #{math.div(64, $base-font-size)}rem; padding-right: #{math.div(24, $base-font-size)}rem; - button, a { + button, + a { @include themify() { color: getThemifyVariable('primary-text-color'); } @@ -39,9 +40,9 @@ .quick-add__icon { display: inline-block; - margin-right:#{math.div(15, $base-font-size)}rem; - width:#{math.div(35, $base-font-size)}rem; - height:#{math.div(35, $base-font-size)}rem; + margin-right: #{math.div(15, $base-font-size)}rem; + width: #{math.div(35, $base-font-size)}rem; + height: #{math.div(35, $base-font-size)}rem; @include icon(); @include themify() { // icon graphic @@ -55,8 +56,8 @@ } & svg { - width:#{math.div(35, $base-font-size)}rem; - height:#{math.div(35, $base-font-size)}rem; + width: #{math.div(35, $base-font-size)}rem; + height: #{math.div(35, $base-font-size)}rem; } } } @@ -87,7 +88,7 @@ .quick-add__item-toggle, .quick-add__item-toggle:focus { cursor: pointer; - + @include themify() { & .quick-add__icon path { fill: getThemifyVariable('table-button-hover-color'); @@ -118,4 +119,3 @@ display: none; } } - diff --git a/client/styles/components/_reset-password.scss b/client/styles/components/_reset-password.scss index de0af012f2..98276ce2bb 100644 --- a/client/styles/components/_reset-password.scss +++ b/client/styles/components/_reset-password.scss @@ -1,4 +1,4 @@ -@use "sass:math"; +@use 'sass:math'; .reset-password__submitted { width: #{math.div(360, $base-font-size)}rem; diff --git a/client/styles/components/_resizer.scss b/client/styles/components/_resizer.scss index bf2b0ada3d..92ec59f178 100644 --- a/client/styles/components/_resizer.scss +++ b/client/styles/components/_resizer.scss @@ -1,16 +1,16 @@ .Resizer { - @include themify() { - background: getThemifyVariable('ide-border-color'); - } - -moz-box-sizing: border-box; - -webkit-box-sizing: border-box; - box-sizing: border-box; - z-index: 1; - opacity: 0.02; - -moz-background-clip: padding; - -webkit-background-clip: padding; - background-clip: padding-box; - z-index: 9999; + @include themify() { + background: getThemifyVariable('ide-border-color'); + } + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + box-sizing: border-box; + z-index: 1; + opacity: 0.02; + -moz-background-clip: padding; + -webkit-background-clip: padding; + background-clip: padding-box; + z-index: 9999; } // .Resizer:hover { @@ -19,33 +19,33 @@ // } .Resizer.horizontal { - height: 10px; - margin: -5px 0; - border-top: 5px solid rgba(255, 255, 255, 0); - border-bottom: 5px solid rgba(255, 255, 255, 0); - cursor: row-resize; - width: 100%; + height: 10px; + margin: -5px 0; + border-top: 5px solid rgba(255, 255, 255, 0); + border-bottom: 5px solid rgba(255, 255, 255, 0); + cursor: row-resize; + width: 100%; } .Resizer.horizontal:hover { - // border-top: 5px solid rgba(0, 0, 0, 0.5); - // border-bottom: 5px solid rgba(0, 0, 0, 0.5); + // border-top: 5px solid rgba(0, 0, 0, 0.5); + // border-bottom: 5px solid rgba(0, 0, 0, 0.5); } .Resizer.vertical { - width: 10px; - margin: 0 -5px; - border-left: 5px solid rgba(255, 255, 255, 0); - border-right: 5px solid rgba(255, 255, 255, 0); - cursor: col-resize; + width: 10px; + margin: 0 -5px; + border-left: 5px solid rgba(255, 255, 255, 0); + border-right: 5px solid rgba(255, 255, 255, 0); + cursor: col-resize; } .Resizer.vertical:hover { - // border-left: 5px solid rgba(0, 0, 0, 0.5); - // border-right: 5px solid rgba(0, 0, 0, 0.5); + // border-left: 5px solid rgba(0, 0, 0, 0.5); + // border-right: 5px solid rgba(0, 0, 0, 0.5); } .Resizer.vertical.disabled, -.Resizer.horizontal.disabled{ - cursor: default; -} \ No newline at end of file +.Resizer.horizontal.disabled { + cursor: default; +} diff --git a/client/styles/components/_searchbar.scss b/client/styles/components/_searchbar.scss index 78e065ab41..929f816f0d 100644 --- a/client/styles/components/_searchbar.scss +++ b/client/styles/components/_searchbar.scss @@ -1,4 +1,4 @@ -@use "sass:math"; +@use 'sass:math'; .searchbar { position: relative; @@ -60,7 +60,8 @@ div.searchbar__button { @include themify() { color: getThemifyVariable('primary-text-color'); background-color: getThemifyVariable('search-clear-background-color'); - &:hover, &:focus { + &:hover, + &:focus { color: getThemifyVariable('search-hover-text-color'); background-color: getThemifyVariable('search-hover-background-color'); } diff --git a/client/styles/components/_share.scss b/client/styles/components/_share.scss index 074fa22f2c..708be43de2 100644 --- a/client/styles/components/_share.scss +++ b/client/styles/components/_share.scss @@ -1,4 +1,4 @@ -@use "sass:math"; +@use 'sass:math'; .share-modal { padding: #{math.div(20, $base-font-size)}rem; @@ -22,4 +22,4 @@ display: flex; flex-wrap: wrap; padding: #{math.div(10, $base-font-size)}rem 0; -} \ No newline at end of file +} diff --git a/client/styles/components/_sidebar.scss b/client/styles/components/_sidebar.scss index 1f1d5972e6..37d8a6ee6f 100644 --- a/client/styles/components/_sidebar.scss +++ b/client/styles/components/_sidebar.scss @@ -1,4 +1,4 @@ -@use "sass:math"; +@use 'sass:math'; .sidebar { display: flex; @@ -45,7 +45,7 @@ .sidebar__file-list { @include themify() { - border-color: getThemifyVariable('ide-border-color') + border-color: getThemifyVariable('ide-border-color'); } border-top: 1px solid; .sidebar--contracted & { @@ -80,7 +80,6 @@ position: relative; @include themify() { color: map-get($theme-map, 'primary-text-color'); - // TODO get this to not affect parent, need to move it into JS &:hover:not(.sidebar__file-item--selected) > .file-item__content { background-color: map-get($theme-map, 'file-hover-color'); } @@ -96,9 +95,6 @@ } } -// to indent each row in the file tree -// not sure how to do this in a better way -// it won't work if the file tree is too nested .file-item__spacer { flex-shrink: 0; .sidebar__file-item & { @@ -206,9 +202,28 @@ display: none; width: 100%; max-width: #{math.div(180, $base-font-size)}rem; + overflow: visible !important; .sidebar__file-item--open > .file-item__content & { display: flex; } + + ul { + overflow: visible !important; + } + + li { + overflow: visible !important; + position: relative; + } + + button { + overflow: visible !important; + } +} + +.sidebar__file-item-option { + position: relative; + overflow: visible !important; } .sidebar__file-item-input { @@ -236,14 +251,16 @@ justify-content: center; align-items: center; @include themify() { - background-color: getThemifyVariable("toolbar-button-background-color"); - & polygon, & path { - fill: getThemifyVariable("toolbar-button-color"); + background-color: getThemifyVariable('toolbar-button-background-color'); + & polygon, + & path { + fill: getThemifyVariable('toolbar-button-color'); } &:hover { - background-color: getThemifyVariable("button-background-hover-color"); - & polygon, & path { - fill: getThemifyVariable("button-hover-color"); + background-color: getThemifyVariable('button-background-hover-color'); + & polygon, + & path { + fill: getThemifyVariable('button-hover-color'); } } } @@ -328,7 +345,114 @@ display: none; width: 100%; max-width: #{math.div(180, $base-font-size)}rem; + overflow: visible !important; .sidebar--project-options & { display: flex; } + + ul { + overflow: visible !important; + } + + li { + position: relative; + overflow: visible !important; + } + + button { + overflow: visible !important; + } +} + +.sidebar__lock-icon { + display: inline-flex; + align-items: center; + justify-content: center; + width: #{math.div(14, $base-font-size)}rem; + height: #{math.div(14, $base-font-size)}rem; + flex-shrink: 0; + + svg { + width: 100%; + height: 100%; + + @include themify() { + color: getThemifyVariable('secondary-text-color'); + fill: currentColor; + } + + path { + fill: currentColor; + } + } +} + +.tooltipped-login { + position: relative; + cursor: not-allowed !important; + display: flex !important; + align-items: center; + gap: #{math.div(6, $base-font-size)}rem; + + @include themify() { + color: getThemifyVariable('secondary-text-color') !important; + } + + > *:not(.tooltipped-login-tooltip) { + opacity: 0.5; + } +} + +.tooltipped-login-tooltip { + position: absolute; + display: none; + z-index: 1000000; + padding: #{math.div(12, $base-font-size)}rem #{math.div(16, $base-font-size)}rem; + font-size: #{math.div(14, $base-font-size)}rem; + font-family: Montserrat, sans-serif; + font-weight: 600; + line-height: 1.5; + text-align: center; + white-space: nowrap; + border-radius: 8px; + box-shadow: 0 8px 24px rgba(0, 0, 0, 0.9), 0 0 0 3px rgba(255, 255, 255, 0.1); + pointer-events: none; + + left: calc(100% + #{math.div(15, $base-font-size)}rem); + top: 50%; + transform: translateY(-50%); + + opacity: 1 !important; + visibility: visible !important; + + background: linear-gradient(135deg, #1a1a1a 0%, #2d2d2d 100%) !important; + color: #ffffff !important; + border: 3px solid #ff006e !important; + text-shadow: 0 2px 4px rgba(0, 0, 0, 0.8); + + &::before { + content: ''; + position: absolute; + top: 50%; + right: 100%; + transform: translateY(-50%); + border: 10px solid transparent; + border-right-color: #ff006e !important; + filter: drop-shadow(-2px 0 4px rgba(0, 0, 0, 0.5)); + } + + &::after { + content: ''; + position: absolute; + top: 50%; + right: calc(100% + 3px); + transform: translateY(-50%); + border: 7px solid transparent; + border-right-color: #1a1a1a !important; + } } + +.tooltipped-login:hover .tooltipped-login-tooltip { + display: block !important; + visibility: visible !important; +} \ No newline at end of file diff --git a/client/styles/components/_sketch-list.scss b/client/styles/components/_sketch-list.scss index 401f575728..9f638d77b9 100644 --- a/client/styles/components/_sketch-list.scss +++ b/client/styles/components/_sketch-list.scss @@ -1,4 +1,4 @@ -@use "sass:math"; +@use 'sass:math'; .sketch-visibility__title { @include themify() { @@ -40,7 +40,7 @@ } .sketch-visibility_ul li::before { - content: "\2022"; + content: '\2022'; @include themify() { color: getThemifyVariable('hint-arrow-background-color'); @@ -50,9 +50,6 @@ margin-right: 10px; } - - - .sketches-table-container { overflow-y: auto; max-width: 100%; @@ -60,7 +57,7 @@ @media (max-width: 770px) { @include themify() { - background-color: getThemifyVariable("modal-background-color"); + background-color: getThemifyVariable('modal-background-color'); } .sketches-table { @@ -79,8 +76,6 @@ flex-direction: column; gap: #{math.div(12, $base-font-size)}rem; - - .sketches-table__row { margin: 0; position: relative; @@ -91,8 +86,10 @@ gap: #{math.div(8, $base-font-size)}rem; @include themify() { - border: 1px solid getThemifyVariable("modal-border-color"); - background-color: getThemifyVariable("search-background-color") !important; + border: 1px solid getThemifyVariable('modal-border-color'); + background-color: getThemifyVariable( + 'search-background-color' + ) !important; } .sketches-table_name { @@ -102,14 +99,13 @@ align-items: center; } - - >td { + > td { padding-left: 0; width: 30%; font-size: #{math.div(14, $base-font-size)}rem; @include themify() { - color: getThemifyVariable("modal-border-color"); + color: getThemifyVariable('modal-border-color'); } } @@ -152,7 +148,7 @@ z-index: 1; @include themify() { - background-color: getThemifyVariable("background-color"); + background-color: getThemifyVariable('background-color'); } } @@ -168,7 +164,7 @@ & svg { margin-left: #{math.div(5, $base-font-size)}rem; @include themify() { - fill: getThemifyVariable("inactive-text-color"); + fill: getThemifyVariable('inactive-text-color'); } } } @@ -178,13 +174,13 @@ padding: #{math.div(3, $base-font-size)}rem 0; @include themify() { - color: getThemifyVariable("inactive-text-color"); + color: getThemifyVariable('inactive-text-color'); } } .sketches-table__header--selected { @include themify() { - border-color: getThemifyVariable("logo-color"); + border-color: getThemifyVariable('logo-color'); } } @@ -200,27 +196,26 @@ .sketches-table__row:nth-child(odd) { @include themify() { - background: getThemifyVariable("table-row-stripe-color"); + background: getThemifyVariable('table-row-stripe-color'); } } -.sketches-table__row>th:nth-child(1) { +.sketches-table__row > th:nth-child(1) { padding-left: #{math.div(12, $base-font-size)}rem; } -.sketches-table__row>td { +.sketches-table__row > td { padding-left: #{math.div(8, $base-font-size)}rem; } .sketches-table__row a { @include themify() { text-decoration: underline; - color: getThemifyVariable("primary-text-color"); + color: getThemifyVariable('primary-text-color'); } - } -.sketches-table__row.is-deleted-or-private>* { +.sketches-table__row.is-deleted-or-private > * { font-style: italic; } @@ -228,7 +223,7 @@ font-size: #{math.div(12, $base-font-size)}rem; @include themify() { - color: getThemifyVariable("inactive-text-color"); + color: getThemifyVariable('inactive-text-color'); } } @@ -251,9 +246,9 @@ font-size: #{math.div(16, $base-font-size)}rem; padding: #{math.div(42, $base-font-size)}rem 0; } -.sketches-table__row a:hover{ +.sketches-table__row a:hover { @include themify() { - color: getThemifyVariable("logo-color"); + color: getThemifyVariable('logo-color'); } text-decoration-thickness: 0.1em; -} \ No newline at end of file +} diff --git a/client/styles/components/_skip-link.scss b/client/styles/components/_skip-link.scss index 09d7d7d60f..cac136e5dd 100644 --- a/client/styles/components/_skip-link.scss +++ b/client/styles/components/_skip-link.scss @@ -1,4 +1,4 @@ -@use "sass:math"; +@use 'sass:math'; .skip_link { left: 50%; @@ -12,7 +12,8 @@ vertical-align: middle; background-color: transparent; font-size: #{math.div(12, $base-font-size)}rem; - line-height: #{math.div(50, $base-font-size)}rem;line-height: 11px; + line-height: #{math.div(50, $base-font-size)}rem; + line-height: 11px; padding: #{math.div(10, $base-font-size)}rem #{math.div(10, $base-font-size)}rem; background: #fff; display: inline-block; diff --git a/client/styles/components/_tabs.scss b/client/styles/components/_tabs.scss index 7f2d953237..f12710a7cf 100644 --- a/client/styles/components/_tabs.scss +++ b/client/styles/components/_tabs.scss @@ -1,4 +1,4 @@ -@use "sass:math"; +@use 'sass:math'; .tabs__titles { display: flex; @@ -12,13 +12,14 @@ .tabs__title { @include themify() { color: getThemifyVariable('inactive-text-color'); - &:hover, &:focus{ + &:hover, + &:focus { color: getThemifyVariable('primary-text-color'); - cursor: pointer; + cursor: pointer; } - &:focus { + &:focus { color: getThemifyVariable('primary-text-color'); - cursor: pointer; + cursor: pointer; } } font-size: #{math.div(12, $base-font-size)}rem; @@ -30,7 +31,8 @@ .react-tabs__tab--selected { @include themify() { - border-bottom: #{math.div(4, $base-font-size)}rem solid getThemifyVariable('button-background-hover-color'); + border-bottom: #{math.div(4, $base-font-size)}rem solid + getThemifyVariable('button-background-hover-color'); } } @@ -54,13 +56,14 @@ .tabs__title { @include themify() { color: getThemifyVariable('inactive-text-color'); - &:hover, &:focus{ + &:hover, + &:focus { color: getThemifyVariable('primary-text-color'); - cursor: pointer; + cursor: pointer; } - &:focus { + &:focus { color: getThemifyVariable('primary-text-color'); - cursor: pointer; + cursor: pointer; } } font-size: #{math.div(12, $base-font-size)}rem; diff --git a/client/styles/components/_timer.scss b/client/styles/components/_timer.scss index c258bf5bf0..ebbc2c14d2 100644 --- a/client/styles/components/_timer.scss +++ b/client/styles/components/_timer.scss @@ -1,4 +1,4 @@ -@use "sass:math"; +@use 'sass:math'; .timer__saved-time { @include themify() { diff --git a/client/styles/components/_toast.scss b/client/styles/components/_toast.scss index c52793c5cb..b3056ba210 100644 --- a/client/styles/components/_toast.scss +++ b/client/styles/components/_toast.scss @@ -1,4 +1,4 @@ -@use "sass:math"; +@use 'sass:math'; .toast { background-color: $toast-background-color; @@ -14,7 +14,7 @@ z-index: 9999; align-items: center; justify-content: space-between; - box-shadow: 0 6px 6px 0 rgba(0,0,0,0.10); + box-shadow: 0 6px 6px 0 rgba(0, 0, 0, 0.1); } .toast__close { @@ -23,4 +23,4 @@ } padding-top: #{math.div(10, $base-font-size)}rem; margin-left: #{math.div(40, $base-font-size)}rem; -} \ No newline at end of file +} diff --git a/client/styles/components/_toggle.scss b/client/styles/components/_toggle.scss index 8d4d73370d..78fa2148bf 100644 --- a/client/styles/components/_toggle.scss +++ b/client/styles/components/_toggle.scss @@ -1,63 +1,63 @@ .visibility__toggle-checkbox { - display: none; + display: none; } .visibility__toggle-label { - position: relative; - cursor: pointer; - width: 50px; - height: 20px; - background: grey; - border-radius: 10px; - transition: background-color 0.3s; - display: flex; - justify-content: center; - align-items: center; + position: relative; + cursor: pointer; + width: 50px; + height: 20px; + background: grey; + border-radius: 10px; + transition: background-color 0.3s; + display: flex; + justify-content: center; + align-items: center; } .lock, .earth { - position: absolute; - height: 12px; - width: 12px; + position: absolute; + height: 12px; + width: 12px; } .lock { - left: 4px; + left: 4px; } .earth { - right: 4px; + right: 4px; } .visibility__toggle-label::after { - content: ''; - position: absolute; - top: 1px; - left: 1px; - width: 18px; - height: 18px; - background: #fff; - border-radius: 50%; - transition: all 0.3s; - display: flex; - justify-content: center; - align-items: center; + content: ''; + position: absolute; + top: 1px; + left: 1px; + width: 18px; + height: 18px; + background: #fff; + border-radius: 50%; + transition: all 0.3s; + display: flex; + justify-content: center; + align-items: center; } -.visibility__toggle-checkbox:checked+.visibility__toggle-label { - background: #ED225D; +.visibility__toggle-checkbox:checked + .visibility__toggle-label { + background: #ed225d; } -.visibility__toggle-checkbox:checked+.visibility__toggle-label::after { - left: calc(100% - 1px); - transform: translateX(-100%); +.visibility__toggle-checkbox:checked + .visibility__toggle-label::after { + left: calc(100% - 1px); + transform: translateX(-100%); } .visibility__toggle-label:active:after { - width: 30px; + width: 30px; } -.visibility__toggle-checkbox:checked+.visibility__toggle-label::after { - animation: slideText 0.3s ease-in-out forwards; -} \ No newline at end of file +.visibility__toggle-checkbox:checked + .visibility__toggle-label::after { + animation: slideText 0.3s ease-in-out forwards; +} diff --git a/client/styles/components/_toolbar.scss b/client/styles/components/_toolbar.scss index b3e30909c1..a03e381ba0 100644 --- a/client/styles/components/_toolbar.scss +++ b/client/styles/components/_toolbar.scss @@ -1,205 +1,205 @@ -@use "sass:math"; +@use 'sass:math'; .toolbar__play-button { - @include themify() { - @extend %toolbar-button; - display: flex; - justify-content: center; - align-items: center; - padding: 0 0 0 #{math.div(3, $base-font-size)}rem; - - &--selected { - @extend %toolbar-button--selected; - } - - &:disabled { - cursor: auto; - - & g, - & path { - fill: getThemifyVariable('button-border-color'); - } - - &:hover { - background-color: getThemifyVariable('toolbar-button-background-color'); - - & g, - & path { - fill: getThemifyVariable('button-border-color'); - } - } - } - } - - margin-right: #{math.div(15, $base-font-size)}rem; - - span { - padding-left: #{math.div(4, $base-font-size)}rem; - display: flex; - align-items: center; - justify-content: center; - width: #{math.div(20, $base-font-size)}rem; - height: #{math.div(20, $base-font-size)}rem; - } + @include themify() { + @extend %toolbar-button; + display: flex; + justify-content: center; + align-items: center; + padding: 0 0 0 #{math.div(3, $base-font-size)}rem; + + &--selected { + @extend %toolbar-button--selected; + } + + &:disabled { + cursor: auto; + + & g, + & path { + fill: getThemifyVariable('button-border-color'); + } + + &:hover { + background-color: getThemifyVariable('toolbar-button-background-color'); + + & g, + & path { + fill: getThemifyVariable('button-border-color'); + } + } + } + } + + margin-right: #{math.div(15, $base-font-size)}rem; + + span { + padding-left: #{math.div(4, $base-font-size)}rem; + display: flex; + align-items: center; + justify-content: center; + width: #{math.div(20, $base-font-size)}rem; + height: #{math.div(20, $base-font-size)}rem; + } } .toolbar__play-sketch-button { - @extend %hidden-element; + @extend %hidden-element; } .toolbar__stop-button { - @include themify() { - @extend %toolbar-button; - display: flex; - justify-content: center; - align-items: center; - margin-right: #{math.div(15, $base-font-size)}rem; - padding: 0; - - &--selected { - @extend %toolbar-button--selected; - } - } - - span { - display: flex; - align-items: center; - justify-content: center; - width: #{math.div(20, $base-font-size)}rem; - height: #{math.div(20, $base-font-size)}rem; - } + @include themify() { + @extend %toolbar-button; + display: flex; + justify-content: center; + align-items: center; + margin-right: #{math.div(15, $base-font-size)}rem; + padding: 0; + + &--selected { + @extend %toolbar-button--selected; + } + } + + span { + display: flex; + align-items: center; + justify-content: center; + width: #{math.div(20, $base-font-size)}rem; + height: #{math.div(20, $base-font-size)}rem; + } } .toolbar__preferences-button { - @include themify() { - @extend %toolbar-button; - display: flex; - justify-content: center; - align-items: center; - padding: 0; - - &--selected { - @extend %toolbar-button--selected; - } - } - - margin-left: auto; - - & span { - padding-left: #{math.div(1, $base-font-size)}rem; - display: flex; - align-items: center; - justify-content: center; - width: #{math.div(20, $base-font-size)}rem; - height: #{math.div(20, $base-font-size)}rem; - } + @include themify() { + @extend %toolbar-button; + display: flex; + justify-content: center; + align-items: center; + padding: 0; + + &--selected { + @extend %toolbar-button--selected; + } + } + + margin-left: auto; + + & span { + padding-left: #{math.div(1, $base-font-size)}rem; + display: flex; + align-items: center; + justify-content: center; + width: #{math.div(20, $base-font-size)}rem; + height: #{math.div(20, $base-font-size)}rem; + } } .toolbar__logo { - margin-right: #{math.div(30, $base-font-size)}rem; + margin-right: #{math.div(30, $base-font-size)}rem; - @include themify() { - & g, - & path { - fill: getThemifyVariable('logo-color'); - } - } + @include themify() { + & g, + & path { + fill: getThemifyVariable('logo-color'); + } + } } .toolbar { - padding: #{math.div(10, $base-font-size)}rem #{math.div(20, $base-font-size)}rem; - display: flex; - align-items: center; + padding: #{math.div(10, $base-font-size)}rem #{math.div(20, $base-font-size)}rem; + display: flex; + align-items: center; - @include themify() { - border-bottom: 1px dashed map-get($theme-map, 'nav-border-color'); - } + @include themify() { + border-bottom: 1px dashed map-get($theme-map, 'nav-border-color'); + } } .lock-icon { - height: 60%; - width: 60%; + height: 60%; + width: 60%; } .unlock-icon { - height: 60%; - width: 60%; + height: 60%; + width: 60%; } .toolbar__project-name-container { - margin-left: #{math.div(10, $base-font-size)}rem; - padding-left: #{math.div(10, $base-font-size)}rem; - display: flex; - align-items: center; + margin-left: #{math.div(10, $base-font-size)}rem; + padding-left: #{math.div(10, $base-font-size)}rem; + display: flex; + align-items: center; - > section { - display: flex; - align-items: center; - justify-content: center; - height: 30px; - width: 30px; - } + > section { + display: flex; + align-items: center; + justify-content: center; + height: 30px; + width: 30px; + } } .toolbar .editable-input__label { - @include themify() { - color: getThemifyVariable('secondary-text-color'); + @include themify() { + color: getThemifyVariable('secondary-text-color'); - & path { - fill: getThemifyVariable('secondary-text-color'); - } - } + & path { + fill: getThemifyVariable('secondary-text-color'); + } + } } .toolbar .editable-input__input { - border: 0; + border: 0; } .toolbar__project-owner { - margin: 0; - @include themify() { - color: getThemifyVariable('secondary-text-color'); - } + margin: 0; + @include themify() { + color: getThemifyVariable('secondary-text-color'); + } } .toolbar__autorefresh-label { - cursor: pointer; + cursor: pointer; - @include themify() { - color: getThemifyVariable('secondary-text-color'); + @include themify() { + color: getThemifyVariable('secondary-text-color'); - &:hover { - color: getThemifyVariable('logo-color'); - } - } + &:hover { + color: getThemifyVariable('logo-color'); + } + } - margin-left: #{math.div(5, $base-font-size)}rem; - font-size: #{math.div(12, $base-font-size)}rem; + margin-left: #{math.div(5, $base-font-size)}rem; + font-size: #{math.div(12, $base-font-size)}rem; } .toolbar__autorefresh { - display: flex; - align-items: center; + display: flex; + align-items: center; } .checkbox__autorefresh { - cursor: pointer; + cursor: pointer; - @include themify() { - accent-color: getThemifyVariable('logo-color'); - } + @include themify() { + accent-color: getThemifyVariable('logo-color'); + } } .toolbar__makeprivate { - display: flex; - align-items: center; - gap: #{math.div(4, $base-font-size)}rem; + display: flex; + align-items: center; + gap: #{math.div(4, $base-font-size)}rem; } .toolbar__togglevisibility { - cursor: pointer; + cursor: pointer; - @include themify() { - accent-color: getThemifyVariable('logo-color'); - } -} \ No newline at end of file + @include themify() { + accent-color: getThemifyVariable('logo-color'); + } +} diff --git a/client/styles/components/_visibility-dropdown.scss b/client/styles/components/_visibility-dropdown.scss index 65aa98c0ef..68ce4a8d30 100644 --- a/client/styles/components/_visibility-dropdown.scss +++ b/client/styles/components/_visibility-dropdown.scss @@ -1,4 +1,4 @@ -@use "sass:math"; +@use 'sass:math'; .visibility-dropdown { position: relative; @@ -19,8 +19,8 @@ .visibility-dropdown__trigger-toolbar { @include themify() { - color: getThemifyVariable("toolbar-button-color"); - background-color: getThemifyVariable("toolbar-button-background-color"); + color: getThemifyVariable('toolbar-button-color'); + background-color: getThemifyVariable('toolbar-button-background-color'); & g, & path { @@ -30,10 +30,12 @@ &:hover { @include themify() { - background-color: getThemifyVariable("button-background-hover-color") !important; - color: getThemifyVariable("button-hover-color") !important; + background-color: getThemifyVariable( + 'button-background-hover-color' + ) !important; + color: getThemifyVariable('button-hover-color') !important; - & g, + & g, & path { fill: getThemifyVariable('button-hover-color') !important; } @@ -52,9 +54,9 @@ border-radius: #{math.div(6, $base-font-size)}rem; @include themify() { - border: 1px solid getThemifyVariable("modal-border-color"); - color: getThemifyVariable("primary-text-color"); - background-color: getThemifyVariable("modal-background-color"); + border: 1px solid getThemifyVariable('modal-border-color'); + color: getThemifyVariable('primary-text-color'); + background-color: getThemifyVariable('modal-background-color'); } } @@ -66,8 +68,8 @@ flex-direction: column; @include themify() { - border-bottom: 1px solid getThemifyVariable("modal-border-color"); - background-color: getThemifyVariable("modal-background-color"); + border-bottom: 1px solid getThemifyVariable('modal-border-color'); + background-color: getThemifyVariable('modal-background-color'); } &:last-child { @@ -76,10 +78,12 @@ &:hover { @include themify() { - background-color: getThemifyVariable("button-background-hover-color") !important; - color: getThemifyVariable("button-hover-color") !important; + background-color: getThemifyVariable( + 'button-background-hover-color' + ) !important; + color: getThemifyVariable('button-hover-color') !important; - & g { + & g { fill: getThemifyVariable('button-hover-color') !important; } } @@ -87,7 +91,7 @@ &.selected { @include themify() { - background-color: getThemifyVariable("table-row-stripe-color"); + background-color: getThemifyVariable('table-row-stripe-color'); } } } @@ -122,7 +126,7 @@ flex-shrink: 0; @include themify() { - stroke: getThemifyVariable("inactive-text-color"); + stroke: getThemifyVariable('inactive-text-color'); } } @@ -132,7 +136,7 @@ height: #{math.div(16, $base-font-size)}rem; @include themify() { - stroke: getThemifyVariable("logo-color"); + stroke: getThemifyVariable('logo-color'); } } @@ -144,7 +148,7 @@ font-size: #{math.div(14, $base-font-size)}rem; @include themify() { - color: getThemifyVariable("inactive-text-color"); + color: getThemifyVariable('inactive-text-color'); } } @@ -163,7 +167,7 @@ } .toolbar .visibility-dropdown__trigger { - font-size: 1rem; + font-size: 1rem; } .toolbar .visibility-icon { diff --git a/client/styles/layout/_dashboard.scss b/client/styles/layout/_dashboard.scss index fea65f2809..4cf22ce4a2 100644 --- a/client/styles/layout/_dashboard.scss +++ b/client/styles/layout/_dashboard.scss @@ -1,4 +1,4 @@ -@use "sass:math"; +@use 'sass:math'; .dashboard-content { display: flex; diff --git a/client/styles/layout/_ide.scss b/client/styles/layout/_ide.scss index 25135595a7..a952a5955b 100644 --- a/client/styles/layout/_ide.scss +++ b/client/styles/layout/_ide.scss @@ -13,7 +13,7 @@ } .toolbar { - width: 100%; + width: 100%; } .sidebar { @@ -43,4 +43,4 @@ .CodeMirror-gutters { display: none; } -} \ No newline at end of file +} diff --git a/client/styles/main.scss b/client/styles/main.scss index 3792c192f1..3da3e4e089 100644 --- a/client/styles/main.scss +++ b/client/styles/main.scss @@ -60,4 +60,4 @@ @import 'components/visibility-dropdown'; @import 'layout/dashboard'; -@import 'layout/ide'; \ No newline at end of file +@import 'layout/ide'; diff --git a/client/tsconfig.json b/client/tsconfig.json index 9e63548a60..7493d90884 100644 --- a/client/tsconfig.json +++ b/client/tsconfig.json @@ -4,8 +4,8 @@ "target": "ES6", "module": "ESNext", "lib": ["DOM", "ESNext"], - "jsx": "react", + "jsx": "react" }, "include": ["./**/*"], "exclude": ["../node_modules", "../server"] -} \ No newline at end of file +} diff --git a/client/utils/codemirror-search.js b/client/utils/codemirror-search.js index 3ed3116a63..09904254fb 100644 --- a/client/utils/codemirror-search.js +++ b/client/utils/codemirror-search.js @@ -399,8 +399,9 @@ function startSearch(cm, state, query) { var searchDialog = document.querySelector('.CodeMirror-dialog'); if (searchDialog) { // check if the file has changed - let currentFileName = document.querySelector('.editor__file-name span') - ?.innerText; + let currentFileName = document.querySelector( + '.editor__file-name span' + )?.innerText; if (state.lastFileName !== currentFileName) { state.lastFileName = currentFileName; @@ -438,9 +439,8 @@ function startSearch(cm, state, query) { cursor.findNext(); var num_match = cm.state.search.annotate.matches.length; if (num_match == 0) { - cm.display.wrapper.querySelector( - '.CodeMirror-search-results' - ).innerText = i18n.t('CodemirrorFindAndReplace.NoResults'); + cm.display.wrapper.querySelector('.CodeMirror-search-results').innerText = + i18n.t('CodemirrorFindAndReplace.NoResults'); cm.removeOverlay(state.overlay, state.caseInsensitive); } else { var next = @@ -450,9 +450,8 @@ function startSearch(cm, state, query) { ); }) + 1; var text_match = next + '/' + num_match; - cm.display.wrapper.querySelector( - '.CodeMirror-search-results' - ).innerText = text_match; + cm.display.wrapper.querySelector('.CodeMirror-search-results').innerText = + text_match; } } } @@ -645,9 +644,8 @@ function findNext(cm, rev, callback) { s.from.ch === cursor.from().ch && s.from.line === cursor.from().line ) + 1; var text_match = next + '/' + num_match; - cm.display.wrapper.querySelector( - '.CodeMirror-search-results' - ).innerText = text_match; + cm.display.wrapper.querySelector('.CodeMirror-search-results').innerText = + text_match; if (callback) callback(cursor.from(), cursor.to()); }); } diff --git a/client/utils/dispatcher.test.ts b/client/utils/dispatcher.test.ts index 48572653c4..282fbb90e3 100644 --- a/client/utils/dispatcher.test.ts +++ b/client/utils/dispatcher.test.ts @@ -12,7 +12,7 @@ describe('dispatcher', () => { beforeEach(() => { origin = 'https://example.com'; - mockFrame = ({ postMessage: jest.fn() } as unknown) as Window; + mockFrame = { postMessage: jest.fn() } as unknown as Window; }); afterEach(() => { @@ -47,8 +47,8 @@ describe('dispatcher', () => { }); it('sends a deep-copied message to all registered frames', () => { - const frame1 = ({ postMessage: jest.fn() } as unknown) as Window; - const frame2 = ({ postMessage: jest.fn() } as unknown) as Window; + const frame1 = { postMessage: jest.fn() } as unknown as Window; + const frame2 = { postMessage: jest.fn() } as unknown as Window; const remove1 = registerFrame(frame1, origin); const remove2 = registerFrame(frame2, origin); diff --git a/client/utils/evaluateExpression.ts b/client/utils/evaluateExpression.ts index 6f8cdf8ada..852942b7d5 100644 --- a/client/utils/evaluateExpression.ts +++ b/client/utils/evaluateExpression.ts @@ -12,33 +12,31 @@ function makeEvaluateExpression(evalInClosure: EvalInClosureFn) { } export function evaluateExpressionWrapper(): (expr: string) => EvalResult { - return makeEvaluateExpression( - (expr: string): EvalResult => { - let newExpr = expr; - let result = null; - let error = false; + return makeEvaluateExpression((expr: string): EvalResult => { + let newExpr = expr; + let result = null; + let error = false; + try { try { - try { - const wrapped = `(${expr})`; - // eslint-disable-next-line no-new-func - const validate = new Function(wrapped); - newExpr = wrapped; - } catch (e) { - // We shouldn't wrap the expression - } - // eslint-disable-next-line no-eval - result = (0, eval)(newExpr); + const wrapped = `(${expr})`; + // eslint-disable-next-line no-new-func + const validate = new Function(wrapped); + newExpr = wrapped; } catch (e) { - if (e instanceof Error) { - result = `${e.name}: ${e.message}`; - } else { - result = String(e); - } - error = true; + // We shouldn't wrap the expression } - return { result, error }; + // eslint-disable-next-line no-eval + result = (0, eval)(newExpr); + } catch (e) { + if (e instanceof Error) { + result = `${e.name}: ${e.message}`; + } else { + result = String(e); + } + error = true; } - ); + return { result, error }; + }); } export const evaluateExpression = evaluateExpressionWrapper(); diff --git a/client/utils/htmlmixed.js b/client/utils/htmlmixed.js index 23a0eacf05..6ca6fa1db9 100644 --- a/client/utils/htmlmixed.js +++ b/client/utils/htmlmixed.js @@ -2,33 +2,50 @@ // Distributed under an MIT license: http://codemirror.net/LICENSE /* eslint-disable */ -(function(mod) { - if (typeof exports == "object" && typeof module == "object") // CommonJS - mod(require("codemirror"), require("codemirror/mode/xml/xml"), require("./p5-javascript"), require("codemirror/mode/css/css")); - else if (typeof define == "function" && define.amd) // AMD - define(["codemirror", "codemirror/mode/xml/xml", "./p5-javascript", "codemirror/mode/css/css"], mod); - else // Plain browser env - mod(CodeMirror); -})(function(CodeMirror) { - "use strict"; +(function (mod) { + if (typeof exports == 'object' && typeof module == 'object') + // CommonJS + mod( + require('codemirror'), + require('codemirror/mode/xml/xml'), + require('./p5-javascript'), + require('codemirror/mode/css/css') + ); + else if (typeof define == 'function' && define.amd) + // AMD + define([ + 'codemirror', + 'codemirror/mode/xml/xml', + './p5-javascript', + 'codemirror/mode/css/css' + ], mod); + // Plain browser env + else mod(CodeMirror); +})(function (CodeMirror) { + 'use strict'; var defaultTags = { script: [ - ["lang", /(javascript|babel)/i, "javascript"], - ["type", /^(?:text|application)\/(?:x-)?(?:java|ecma)script$|^$/i, "javascript"], - ["type", /./, "text/plain"], - [null, null, "javascript"] + ['lang', /(javascript|babel)/i, 'javascript'], + [ + 'type', + /^(?:text|application)\/(?:x-)?(?:java|ecma)script$|^$/i, + 'javascript' + ], + ['type', /./, 'text/plain'], + [null, null, 'javascript'] ], - style: [ - ["lang", /^css$/i, "css"], - ["type", /^(text\/)?(x-)?(stylesheet|css)$/i, "css"], - ["type", /./, "text/plain"], - [null, null, "css"] + style: [ + ['lang', /^css$/i, 'css'], + ['type', /^(text\/)?(x-)?(stylesheet|css)$/i, 'css'], + ['type', /./, 'text/plain'], + [null, null, 'css'] ] }; function maybeBackup(stream, pat, style) { - var cur = stream.current(), close = cur.search(pat); + var cur = stream.current(), + close = cur.search(pat); if (close > -1) { stream.backUp(cur.length - close); } else if (cur.match(/<\/?$/)) { @@ -42,112 +59,154 @@ function getAttrRegexp(attr) { var regexp = attrRegexpCache[attr]; if (regexp) return regexp; - return attrRegexpCache[attr] = new RegExp("\\s+" + attr + "\\s*=\\s*('|\")?([^'\"]+)('|\")?\\s*"); + return (attrRegexpCache[attr] = new RegExp( + '\\s+' + attr + '\\s*=\\s*(\'|")?([^\'"]+)(\'|")?\\s*' + )); } function getAttrValue(text, attr) { - var match = text.match(getAttrRegexp(attr)) - return match ? /^\s*(.*?)\s*$/.exec(match[2])[1] : "" + var match = text.match(getAttrRegexp(attr)); + return match ? /^\s*(.*?)\s*$/.exec(match[2])[1] : ''; } function getTagRegexp(tagName, anchored) { - return new RegExp((anchored ? "^" : "") + "<\/\s*" + tagName + "\s*>", "i"); + return new RegExp((anchored ? '^' : '') + '', 'i'); } function addTags(from, to) { for (var tag in from) { var dest = to[tag] || (to[tag] = []); var source = from[tag]; - for (var i = source.length - 1; i >= 0; i--) - dest.unshift(source[i]) + for (var i = source.length - 1; i >= 0; i--) dest.unshift(source[i]); } } function findMatchingMode(tagInfo, tagText) { for (var i = 0; i < tagInfo.length; i++) { var spec = tagInfo[i]; - if (!spec[0] || spec[1].test(getAttrValue(tagText, spec[0]))) return spec[2]; + if (!spec[0] || spec[1].test(getAttrValue(tagText, spec[0]))) + return spec[2]; } } - CodeMirror.defineMode("htmlmixed", function (config, parserConfig) { - var htmlMode = CodeMirror.getMode(config, { - name: "xml", - htmlMode: true, - multilineTagIndentFactor: parserConfig.multilineTagIndentFactor, - multilineTagIndentPastTag: parserConfig.multilineTagIndentPastTag - }); - - var tags = {}; - var configTags = parserConfig && parserConfig.tags, configScript = parserConfig && parserConfig.scriptTypes; - addTags(defaultTags, tags); - if (configTags) addTags(configTags, tags); - if (configScript) for (var i = configScript.length - 1; i >= 0; i--) - tags.script.unshift(["type", configScript[i].matches, configScript[i].mode]) - - function html(stream, state) { - var style = htmlMode.token(stream, state.htmlState), tag = /\btag\b/.test(style), tagName - if (tag && !/[<>\s\/]/.test(stream.current()) && - (tagName = state.htmlState.tagName && state.htmlState.tagName.toLowerCase()) && - tags.hasOwnProperty(tagName)) { - state.inTag = tagName + " " - } else if (state.inTag && tag && />$/.test(stream.current())) { - var inTag = /^([\S]+) (.*)/.exec(state.inTag) - state.inTag = null - var modeSpec = stream.current() == ">" && findMatchingMode(tags[inTag[1]], inTag[2]) - var mode = CodeMirror.getMode(config, modeSpec) - var endTagA = getTagRegexp(inTag[1], true), endTag = getTagRegexp(inTag[1], false); - state.token = function (stream, state) { - if (stream.match(endTagA, false)) { - state.token = html; - state.localState = state.localMode = null; - return null; - } - return maybeBackup(stream, endTag, state.localMode.token(stream, state.localState)); - }; - state.localMode = mode; - state.localState = CodeMirror.startState(mode, htmlMode.indent(state.htmlState, "")); - } else if (state.inTag) { - state.inTag += stream.current() - if (stream.eol()) state.inTag += " " - } - return style; - }; - - return { - startState: function () { - var state = CodeMirror.startState(htmlMode); - return {token: html, inTag: null, localMode: null, localState: null, htmlState: state}; - }, - - copyState: function (state) { - var local; - if (state.localState) { - local = CodeMirror.copyState(state.localMode, state.localState); + CodeMirror.defineMode( + 'htmlmixed', + function (config, parserConfig) { + var htmlMode = CodeMirror.getMode(config, { + name: 'xml', + htmlMode: true, + multilineTagIndentFactor: parserConfig.multilineTagIndentFactor, + multilineTagIndentPastTag: parserConfig.multilineTagIndentPastTag + }); + + var tags = {}; + var configTags = parserConfig && parserConfig.tags, + configScript = parserConfig && parserConfig.scriptTypes; + addTags(defaultTags, tags); + if (configTags) addTags(configTags, tags); + if (configScript) + for (var i = configScript.length - 1; i >= 0; i--) + tags.script.unshift([ + 'type', + configScript[i].matches, + configScript[i].mode + ]); + + function html(stream, state) { + var style = htmlMode.token(stream, state.htmlState), + tag = /\btag\b/.test(style), + tagName; + if ( + tag && + !/[<>\s\/]/.test(stream.current()) && + (tagName = + state.htmlState.tagName && state.htmlState.tagName.toLowerCase()) && + tags.hasOwnProperty(tagName) + ) { + state.inTag = tagName + ' '; + } else if (state.inTag && tag && />$/.test(stream.current())) { + var inTag = /^([\S]+) (.*)/.exec(state.inTag); + state.inTag = null; + var modeSpec = + stream.current() == '>' && + findMatchingMode(tags[inTag[1]], inTag[2]); + var mode = CodeMirror.getMode(config, modeSpec); + var endTagA = getTagRegexp(inTag[1], true), + endTag = getTagRegexp(inTag[1], false); + state.token = function (stream, state) { + if (stream.match(endTagA, false)) { + state.token = html; + state.localState = state.localMode = null; + return null; + } + return maybeBackup( + stream, + endTag, + state.localMode.token(stream, state.localState) + ); + }; + state.localMode = mode; + state.localState = CodeMirror.startState( + mode, + htmlMode.indent(state.htmlState, '') + ); + } else if (state.inTag) { + state.inTag += stream.current(); + if (stream.eol()) state.inTag += ' '; } - return {token: state.token, inTag: state.inTag, - localMode: state.localMode, localState: local, - htmlState: CodeMirror.copyState(htmlMode, state.htmlState)}; - }, - - token: function (stream, state) { - return state.token(stream, state); - }, - - indent: function (state, textAfter) { - if (!state.localMode || /^\s*<\//.test(textAfter)) - return htmlMode.indent(state.htmlState, textAfter); - else if (state.localMode.indent) - return state.localMode.indent(state.localState, textAfter); - else - return CodeMirror.Pass; - }, - - innerMode: function (state) { - return {state: state.localState || state.htmlState, mode: state.localMode || htmlMode}; + return style; } - }; - }, "xml", "javascript", "css"); - CodeMirror.defineMIME("text/html", "htmlmixed"); + return { + startState: function () { + var state = CodeMirror.startState(htmlMode); + return { + token: html, + inTag: null, + localMode: null, + localState: null, + htmlState: state + }; + }, + + copyState: function (state) { + var local; + if (state.localState) { + local = CodeMirror.copyState(state.localMode, state.localState); + } + return { + token: state.token, + inTag: state.inTag, + localMode: state.localMode, + localState: local, + htmlState: CodeMirror.copyState(htmlMode, state.htmlState) + }; + }, + + token: function (stream, state) { + return state.token(stream, state); + }, + + indent: function (state, textAfter) { + if (!state.localMode || /^\s*<\//.test(textAfter)) + return htmlMode.indent(state.htmlState, textAfter); + else if (state.localMode.indent) + return state.localMode.indent(state.localState, textAfter); + else return CodeMirror.Pass; + }, + + innerMode: function (state) { + return { + state: state.localState || state.htmlState, + mode: state.localMode || htmlMode + }; + } + }; + }, + 'xml', + 'javascript', + 'css' + ); + + CodeMirror.defineMIME('text/html', 'htmlmixed'); }); diff --git a/client/utils/p5-instance-methods-and-creators.json b/client/utils/p5-instance-methods-and-creators.json index 2e96ed4205..e386714b27 100644 --- a/client/utils/p5-instance-methods-and-creators.json +++ b/client/utils/p5-instance-methods-and-creators.json @@ -1,16 +1,7 @@ { "p5.Color": { - "createMethods": [ - "color", - "p5.Color" - ], - "methods": [ - "setAlpha", - "setBlue", - "setGreen", - "setRed", - "toString" - ] + "createMethods": ["color", "p5.Color"], + "methods": ["setAlpha", "setBlue", "setGreen", "setRed", "toString"] }, "p5.Geometry": { "createMethods": [ @@ -66,10 +57,7 @@ ] }, "p5.Camera": { - "createMethods": [ - "createCamera", - "p5.Camera" - ], + "createMethods": ["createCamera", "p5.Camera"], "methods": [ "camera", "centerX", @@ -147,18 +135,8 @@ ] }, "p5.File": { - "createMethods": [ - "createFileInput", - "p5.File" - ], - "methods": [ - "data", - "file", - "name", - "size", - "subtype", - "type" - ] + "createMethods": ["createFileInput", "p5.File"], + "methods": ["data", "file", "name", "size", "subtype", "type"] }, "p5.Shader": { "createMethods": [ @@ -168,18 +146,10 @@ "p5.Shader", "shader" ], - "methods": [ - "copyToContext", - "inspectHooks", - "modify", - "setUniform" - ] + "methods": ["copyToContext", "inspectHooks", "modify", "setUniform"] }, "p5.Framebuffer": { - "createMethods": [ - "createFramebuffer", - "p5.Framebuffer" - ], + "createMethods": ["createFramebuffer", "p5.Framebuffer"], "methods": [ "autoSized", "begin", @@ -198,23 +168,11 @@ ] }, "p5.Graphics": { - "createMethods": [ - "createGraphics", - "p5.Graphics" - ], - "methods": [ - "createFramebuffer", - "remove", - "reset" - ] + "createMethods": ["createGraphics", "p5.Graphics"], + "methods": ["createFramebuffer", "remove", "reset"] }, "p5.Image": { - "createMethods": [ - "createImage", - "get", - "loadImage", - "p5.Image" - ], + "createMethods": ["createImage", "get", "loadImage", "p5.Image"], "methods": [ "blend", "copy", @@ -240,9 +198,7 @@ ] }, "p5.NumberDict": { - "createMethods": [ - "createNumberDict" - ], + "createMethods": ["createNumberDict"], "methods": [ "add", "div", @@ -255,16 +211,11 @@ ] }, "p5.StringDict": { - "createMethods": [ - "createStringDict" - ], + "createMethods": ["createStringDict"], "methods": [] }, "p5.Vector": { - "createMethods": [ - "createVector", - "p5.Vector" - ], + "createMethods": ["createVector", "p5.Vector"], "methods": [ "add", "angleBetween", @@ -302,31 +253,15 @@ ] }, "p5.PrintWriter": { - "createMethods": [ - "createWriter", - "p5.PrintWriter" - ], - "methods": [ - "clear", - "close", - "print", - "write" - ] + "createMethods": ["createWriter", "p5.PrintWriter"], + "methods": ["clear", "close", "print", "write"] }, "p5.Font": { - "createMethods": [ - "loadFont" - ], - "methods": [ - "font", - "textBounds", - "textToPoints" - ] + "createMethods": ["loadFont"], + "methods": ["font", "textBounds", "textToPoints"] }, "p5.Table": { - "createMethods": [ - "loadTable" - ], + "createMethods": ["loadTable"], "methods": [ "addColumn", "addRow", @@ -357,9 +292,7 @@ ] }, "p5.XML": { - "createMethods": [ - "loadXML" - ], + "createMethods": ["loadXML"], "methods": [ "addChild", "getAttributeCount", @@ -433,12 +366,7 @@ }, "p5.Gain": { "createMethods": [], - "methods": [ - "amp", - "connect", - "disconnect", - "setInput" - ] + "methods": ["amp", "connect", "disconnect", "setInput"] }, "p5.MonoSynth": { "createMethods": [], @@ -456,9 +384,7 @@ }, "p5.Noise": { "createMethods": [], - "methods": [ - "setType" - ] + "methods": ["setType"] }, "p5.Oscillator": { "createMethods": [], @@ -518,16 +444,11 @@ }, "p5.PeakDetect": { "createMethods": [], - "methods": [ - "onPeak", - "update" - ] + "methods": ["onPeak", "update"] }, "p5.Phrase": { "createMethods": [], - "methods": [ - "sequence" - ] + "methods": ["sequence"] }, "p5.PolySynth": { "createMethods": [], @@ -547,30 +468,15 @@ }, "p5.Pulse": { "createMethods": [], - "methods": [ - "width" - ] + "methods": ["width"] }, "p5.Reverb": { "createMethods": [], - "methods": [ - "amp", - "connect", - "disconnect", - "process", - "set" - ] + "methods": ["amp", "connect", "disconnect", "process", "set"] }, "p5.Score": { "createMethods": [], - "methods": [ - "loop", - "noLoop", - "pause", - "setBPM", - "start", - "stop" - ] + "methods": ["loop", "noLoop", "pause", "setBPM", "start", "stop"] }, "p5.SoundFile": { "createMethods": [], @@ -626,22 +532,11 @@ }, "p5.SoundRecorder": { "createMethods": [], - "methods": [ - "record", - "setInput", - "stop" - ] + "methods": ["record", "setInput", "stop"] }, "p5.TableRow": { "createMethods": [], - "methods": [ - "get", - "getNum", - "getString", - "set", - "setNum", - "setString" - ] + "methods": ["get", "getNum", "getString", "set", "setNum", "setString"] }, "p5.TypedDict": { "createMethods": [], @@ -658,4 +553,4 @@ "size" ] } -} \ No newline at end of file +} diff --git a/client/utils/p5-javascript.js b/client/utils/p5-javascript.js index af34681c07..746a12e93b 100644 --- a/client/utils/p5-javascript.js +++ b/client/utils/p5-javascript.js @@ -2,956 +2,1368 @@ // Distributed under an MIT license: https://codemirror.net/LICENSE /*eslint-disable*/ -var p5_javascript_template = require("./p5-keywords"); +var p5_javascript_template = require('./p5-keywords'); var p5FunctionKeywords = p5_javascript_template.p5FunctionKeywords; var p5VariableKeywords = p5_javascript_template.p5VariableKeywords; -(function(mod) { - if (typeof exports == "object" && typeof module == "object") // CommonJS - mod(require("codemirror")); - else if (typeof define == "function" && define.amd) // AMD - define(["codemirror"], mod); - else // Plain browser env - mod(CodeMirror); -})(function(CodeMirror) { -"use strict"; - -CodeMirror.defineMode("javascript", function(config, parserConfig) { - var indentUnit = config.indentUnit; - var statementIndent = parserConfig.statementIndent; - var jsonldMode = parserConfig.jsonld; - var jsonMode = parserConfig.json || jsonldMode; - var isTS = parserConfig.typescript; - var wordRE = parserConfig.wordCharacters || /[\w$\xa1-\uffff]/; - - // Tokenizer - var keywords = function(){ - function kw(type) {return {type: type, style: "keyword"};} - var A = kw("keyword a"), B = kw("keyword b"), C = kw("keyword c"); - var operator = kw("operator"), atom = {type: "atom", style: "atom"}; - - var jsKeywords = { - "if": kw("if"), "while": A, "with": A, "else": B, "do": B, "try": B, "finally": B, - "return": C, "break": C, "continue": C, "new": kw("new"), "delete": C, "throw": C, "debugger": C, - "var": kw("var"), "const": kw("var"), "let": kw("var"), - "function": kw("function"), "catch": kw("catch"), - "for": kw("for"), "switch": kw("switch"), "case": kw("case"), "default": kw("default"), - "in": operator, "typeof": operator, "instanceof": operator, - "true": atom, "false": atom, "null": atom, "undefined": atom, "NaN": atom, "Infinity": atom, - "this": kw("this"), "class": kw("class"), "super": kw("atom"), - "yield": C, "export": kw("export"), "import": kw("import"), "extends": C, - "await": C, "async": kw("async") - }; +(function (mod) { + if (typeof exports == 'object' && typeof module == 'object') + // CommonJS + mod(require('codemirror')); + else if (typeof define == 'function' && define.amd) + // AMD + define(['codemirror'], mod); // Plain browser env + else mod(CodeMirror); +})(function (CodeMirror) { + 'use strict'; - for (var attr in p5FunctionKeywords) { - jsKeywords[attr] = p5FunctionKeywords[attr]; - } + CodeMirror.defineMode('javascript', function (config, parserConfig) { + var indentUnit = config.indentUnit; + var statementIndent = parserConfig.statementIndent; + var jsonldMode = parserConfig.jsonld; + var jsonMode = parserConfig.json || jsonldMode; + var isTS = parserConfig.typescript; + var wordRE = parserConfig.wordCharacters || /[\w$\xa1-\uffff]/; - for (var attr in p5VariableKeywords) { - jsKeywords[attr] = p5VariableKeywords[attr]; - } + // Tokenizer + var keywords = (function () { + function kw(type) { + return { type: type, style: 'keyword' }; + } + var A = kw('keyword a'), + B = kw('keyword b'), + C = kw('keyword c'); + var operator = kw('operator'), + atom = { type: 'atom', style: 'atom' }; + + var jsKeywords = { + if: kw('if'), + while: A, + with: A, + else: B, + do: B, + try: B, + finally: B, + return: C, + break: C, + continue: C, + new: kw('new'), + delete: C, + throw: C, + debugger: C, + var: kw('var'), + const: kw('var'), + let: kw('var'), + function: kw('function'), + catch: kw('catch'), + for: kw('for'), + switch: kw('switch'), + case: kw('case'), + default: kw('default'), + in: operator, + typeof: operator, + instanceof: operator, + true: atom, + false: atom, + null: atom, + undefined: atom, + NaN: atom, + Infinity: atom, + this: kw('this'), + class: kw('class'), + super: kw('atom'), + yield: C, + export: kw('export'), + import: kw('import'), + extends: C, + await: C, + async: kw('async') + }; + + for (var attr in p5FunctionKeywords) { + jsKeywords[attr] = p5FunctionKeywords[attr]; + } - // Extend the 'normal' keywords with the TypeScript language extensions - if (isTS) { - var type = {type: "variable", style: "variable-3"}; - var tsKeywords = { - // object-like things - "interface": kw("class"), - "implements": C, - "namespace": C, - "module": kw("module"), - "enum": kw("module"), - "type": kw("type"), + for (var attr in p5VariableKeywords) { + jsKeywords[attr] = p5VariableKeywords[attr]; + } - // scope modifiers - "public": kw("modifier"), - "private": kw("modifier"), - "protected": kw("modifier"), - "abstract": kw("modifier"), + // Extend the 'normal' keywords with the TypeScript language extensions + if (isTS) { + var type = { type: 'variable', style: 'variable-3' }; + var tsKeywords = { + // object-like things + interface: kw('class'), + implements: C, + namespace: C, + module: kw('module'), + enum: kw('module'), + type: kw('type'), - // operators - "as": operator, + // scope modifiers + public: kw('modifier'), + private: kw('modifier'), + protected: kw('modifier'), + abstract: kw('modifier'), - // types - "string": type, "number": type, "boolean": type, "any": type - }; + // operators + as: operator, - for (var attr in tsKeywords) { - jsKeywords[attr] = tsKeywords[attr]; - } - } - - return jsKeywords; -}(); - - var isOperatorChar = /[+\-*&%=<>!?|~^@]/; - var isJsonldKeyword = /^@(context|id|value|language|type|container|list|set|reverse|index|base|vocab|graph)"/; - - function readRegexp(stream) { - var escaped = false, next, inSet = false; - while ((next = stream.next()) != null) { - if (!escaped) { - if (next == "/" && !inSet) return; - if (next == "[") inSet = true; - else if (inSet && next == "]") inSet = false; - } - escaped = !escaped && next == "\\"; - } - } - - // Used as scratch variables to communicate multiple values without - // consing up tons of objects. - var type, content; - function ret(tp, style, cont) { - type = tp; content = cont; - return style; - } - function tokenBase(stream, state) { - var ch = stream.next(); - if (ch == '"' || ch == "'") { - state.tokenize = tokenString(ch); - return state.tokenize(stream, state); - } else if (ch == "." && stream.match(/^\d+(?:[eE][+\-]?\d+)?/)) { - return ret("number", "number"); - } else if (ch == "." && stream.match("..")) { - return ret("spread", "meta"); - } else if (/[\[\]{}\(\),;\:\.]/.test(ch)) { - return ret(ch); - } else if (ch == "=" && stream.eat(">")) { - return ret("=>", "operator"); - } else if (ch == "0" && stream.match(/^(?:x[\da-f]+|o[0-7]+|b[01]+)n?/i)) { - return ret("number", "number"); - } else if (/\d/.test(ch)) { - stream.match(/^\d*(?:n|(?:\.\d*)?(?:[eE][+\-]?\d+)?)?/); - return ret("number", "number"); - } else if (ch == "/") { - if (stream.eat("*")) { - state.tokenize = tokenComment; - return tokenComment(stream, state); - } else if (stream.eat("/")) { - stream.skipToEnd(); - return ret("comment", "comment"); - } else if (expressionAllowed(stream, state, 1)) { - readRegexp(stream); - stream.match(/^\b(([gimyus])(?![gimyus]*\2))+\b/); - return ret("regexp", "string-2"); - } else { - stream.eat("="); - return ret("operator", "operator", stream.current()); - } - } else if (ch == "`") { - state.tokenize = tokenQuasi; - return tokenQuasi(stream, state); - } else if (ch == "#") { - stream.skipToEnd(); - return ret("error", "error"); - } else if (isOperatorChar.test(ch)) { - if (ch != ">" || !state.lexical || state.lexical.type != ">") { - if (stream.eat("=")) { - if (ch == "!" || ch == "=") stream.eat("=") - } else if (/[<>*+\-]/.test(ch)) { - stream.eat(ch) - if (ch == ">") stream.eat(ch) + // types + string: type, + number: type, + boolean: type, + any: type + }; + + for (var attr in tsKeywords) { + jsKeywords[attr] = tsKeywords[attr]; } } - return ret("operator", "operator", stream.current()); - } else if (wordRE.test(ch)) { - stream.eatWhile(wordRE); - var word = stream.current() - if (keywords.propertyIsEnumerable(word)) { - var kw = keywords[word] - return ret(kw.type, kw.style, word) + + return jsKeywords; + })(); + + var isOperatorChar = /[+\-*&%=<>!?|~^@]/; + var isJsonldKeyword = + /^@(context|id|value|language|type|container|list|set|reverse|index|base|vocab|graph)"/; + + function readRegexp(stream) { + var escaped = false, + next, + inSet = false; + while ((next = stream.next()) != null) { + if (!escaped) { + if (next == '/' && !inSet) return; + if (next == '[') inSet = true; + else if (inSet && next == ']') inSet = false; + } + escaped = !escaped && next == '\\'; } - if (state.lastType != "." && word == "async" && stream.match(/^(\s|\/\*.*?\*\/)*[\[\(\w]/, false)) - return ret("async", "keyword", word) - return ret("variable", "variable", word) } - } - function tokenString(quote) { - return function(stream, state) { - var escaped = false, next; - if (jsonldMode && stream.peek() == "@" && stream.match(isJsonldKeyword)){ - state.tokenize = tokenBase; - return ret("jsonld-keyword", "meta"); + // Used as scratch variables to communicate multiple values without + // consing up tons of objects. + var type, content; + function ret(tp, style, cont) { + type = tp; + content = cont; + return style; + } + function tokenBase(stream, state) { + var ch = stream.next(); + if (ch == '"' || ch == "'") { + state.tokenize = tokenString(ch); + return state.tokenize(stream, state); + } else if (ch == '.' && stream.match(/^\d+(?:[eE][+\-]?\d+)?/)) { + return ret('number', 'number'); + } else if (ch == '.' && stream.match('..')) { + return ret('spread', 'meta'); + } else if (/[\[\]{}\(\),;\:\.]/.test(ch)) { + return ret(ch); + } else if (ch == '=' && stream.eat('>')) { + return ret('=>', 'operator'); + } else if ( + ch == '0' && + stream.match(/^(?:x[\da-f]+|o[0-7]+|b[01]+)n?/i) + ) { + return ret('number', 'number'); + } else if (/\d/.test(ch)) { + stream.match(/^\d*(?:n|(?:\.\d*)?(?:[eE][+\-]?\d+)?)?/); + return ret('number', 'number'); + } else if (ch == '/') { + if (stream.eat('*')) { + state.tokenize = tokenComment; + return tokenComment(stream, state); + } else if (stream.eat('/')) { + stream.skipToEnd(); + return ret('comment', 'comment'); + } else if (expressionAllowed(stream, state, 1)) { + readRegexp(stream); + stream.match(/^\b(([gimyus])(?![gimyus]*\2))+\b/); + return ret('regexp', 'string-2'); + } else { + stream.eat('='); + return ret('operator', 'operator', stream.current()); + } + } else if (ch == '`') { + state.tokenize = tokenQuasi; + return tokenQuasi(stream, state); + } else if (ch == '#') { + stream.skipToEnd(); + return ret('error', 'error'); + } else if (isOperatorChar.test(ch)) { + if (ch != '>' || !state.lexical || state.lexical.type != '>') { + if (stream.eat('=')) { + if (ch == '!' || ch == '=') stream.eat('='); + } else if (/[<>*+\-]/.test(ch)) { + stream.eat(ch); + if (ch == '>') stream.eat(ch); + } + } + return ret('operator', 'operator', stream.current()); + } else if (wordRE.test(ch)) { + stream.eatWhile(wordRE); + var word = stream.current(); + if (keywords.propertyIsEnumerable(word)) { + var kw = keywords[word]; + return ret(kw.type, kw.style, word); + } + if ( + state.lastType != '.' && + word == 'async' && + stream.match(/^(\s|\/\*.*?\*\/)*[\[\(\w]/, false) + ) + return ret('async', 'keyword', word); + return ret('variable', 'variable', word); } + } + + function tokenString(quote) { + return function (stream, state) { + var escaped = false, + next; + if ( + jsonldMode && + stream.peek() == '@' && + stream.match(isJsonldKeyword) + ) { + state.tokenize = tokenBase; + return ret('jsonld-keyword', 'meta'); + } + while ((next = stream.next()) != null) { + if (next == quote && !escaped) break; + escaped = !escaped && next == '\\'; + } + if (!escaped) state.tokenize = tokenBase; + return ret('string', 'string'); + }; + } + + function tokenComment(stream, state) { + var maybeEnd = false, + ch; + while ((ch = stream.next())) { + if (ch == '/' && maybeEnd) { + state.tokenize = tokenBase; + break; + } + maybeEnd = ch == '*'; + } + return ret('comment', 'comment'); + } + + function tokenQuasi(stream, state) { + var escaped = false, + next; while ((next = stream.next()) != null) { - if (next == quote && !escaped) break; - escaped = !escaped && next == "\\"; + if (!escaped && (next == '`' || (next == '$' && stream.eat('{')))) { + state.tokenize = tokenBase; + break; + } + escaped = !escaped && next == '\\'; } - if (!escaped) state.tokenize = tokenBase; - return ret("string", "string"); + return ret('quasi', 'string-2', stream.current()); + } + + var brackets = '([{}])'; + // This is a crude lookahead trick to try and notice that we're + // parsing the argument patterns for a fat-arrow function before we + // actually hit the arrow token. It only works if the arrow is on + // the same line as the arguments and there's no strange noise + // (comments) in between. Fallback is to only notice when we hit the + // arrow, and not declare the arguments as locals for the arrow + // body. + function findFatArrow(stream, state) { + if (state.fatArrowAt) state.fatArrowAt = null; + var arrow = stream.string.indexOf('=>', stream.start); + if (arrow < 0) return; + + if (isTS) { + // Try to skip TypeScript return type declarations after the arguments + var m = /:\s*(?:\w+(?:<[^>]*>|\[\])?|\{[^}]*\})\s*$/.exec( + stream.string.slice(stream.start, arrow) + ); + if (m) arrow = m.index; + } + + var depth = 0, + sawSomething = false; + for (var pos = arrow - 1; pos >= 0; --pos) { + var ch = stream.string.charAt(pos); + var bracket = brackets.indexOf(ch); + if (bracket >= 0 && bracket < 3) { + if (!depth) { + ++pos; + break; + } + if (--depth == 0) { + if (ch == '(') sawSomething = true; + break; + } + } else if (bracket >= 3 && bracket < 6) { + ++depth; + } else if (wordRE.test(ch)) { + sawSomething = true; + } else if (/["'\/]/.test(ch)) { + return; + } else if (sawSomething && !depth) { + ++pos; + break; + } + } + if (sawSomething && !depth) state.fatArrowAt = pos; + } + + // Parser + + var atomicTypes = { + atom: true, + number: true, + variable: true, + string: true, + regexp: true, + this: true, + 'jsonld-keyword': true }; - } - - function tokenComment(stream, state) { - var maybeEnd = false, ch; - while (ch = stream.next()) { - if (ch == "/" && maybeEnd) { - state.tokenize = tokenBase; - break; - } - maybeEnd = (ch == "*"); - } - return ret("comment", "comment"); - } - - function tokenQuasi(stream, state) { - var escaped = false, next; - while ((next = stream.next()) != null) { - if (!escaped && (next == "`" || next == "$" && stream.eat("{"))) { - state.tokenize = tokenBase; - break; - } - escaped = !escaped && next == "\\"; - } - return ret("quasi", "string-2", stream.current()); - } - - var brackets = "([{}])"; - // This is a crude lookahead trick to try and notice that we're - // parsing the argument patterns for a fat-arrow function before we - // actually hit the arrow token. It only works if the arrow is on - // the same line as the arguments and there's no strange noise - // (comments) in between. Fallback is to only notice when we hit the - // arrow, and not declare the arguments as locals for the arrow - // body. - function findFatArrow(stream, state) { - if (state.fatArrowAt) state.fatArrowAt = null; - var arrow = stream.string.indexOf("=>", stream.start); - if (arrow < 0) return; - - if (isTS) { // Try to skip TypeScript return type declarations after the arguments - var m = /:\s*(?:\w+(?:<[^>]*>|\[\])?|\{[^}]*\})\s*$/.exec(stream.string.slice(stream.start, arrow)) - if (m) arrow = m.index - } - - var depth = 0, sawSomething = false; - for (var pos = arrow - 1; pos >= 0; --pos) { - var ch = stream.string.charAt(pos); - var bracket = brackets.indexOf(ch); - if (bracket >= 0 && bracket < 3) { - if (!depth) { ++pos; break; } - if (--depth == 0) { if (ch == "(") sawSomething = true; break; } - } else if (bracket >= 3 && bracket < 6) { - ++depth; - } else if (wordRE.test(ch)) { - sawSomething = true; - } else if (/["'\/]/.test(ch)) { - return; - } else if (sawSomething && !depth) { - ++pos; - break; - } - } - if (sawSomething && !depth) state.fatArrowAt = pos; - } - - // Parser - - var atomicTypes = {"atom": true, "number": true, "variable": true, "string": true, "regexp": true, "this": true, "jsonld-keyword": true}; - - function JSLexical(indented, column, type, align, prev, info) { - this.indented = indented; - this.column = column; - this.type = type; - this.prev = prev; - this.info = info; - if (align != null) this.align = align; - } - - function inScope(state, varname) { - for (var v = state.localVars; v; v = v.next) - if (v.name == varname) return true; - for (var cx = state.context; cx; cx = cx.prev) { - for (var v = cx.vars; v; v = v.next) + + function JSLexical(indented, column, type, align, prev, info) { + this.indented = indented; + this.column = column; + this.type = type; + this.prev = prev; + this.info = info; + if (align != null) this.align = align; + } + + function inScope(state, varname) { + for (var v = state.localVars; v; v = v.next) if (v.name == varname) return true; + for (var cx = state.context; cx; cx = cx.prev) { + for (var v = cx.vars; v; v = v.next) if (v.name == varname) return true; + } } - } - - function parseJS(state, style, type, content, stream) { - var cc = state.cc; - // Communicate our context to the combinators. - // (Less wasteful than consing up a hundred closures on every call.) - cx.state = state; cx.stream = stream; cx.marked = null, cx.cc = cc; cx.style = style; - - if (!state.lexical.hasOwnProperty("align")) - state.lexical.align = true; - - while(true) { - var combinator = cc.length ? cc.pop() : jsonMode ? expression : statement; - if (combinator(type, content)) { - while(cc.length && cc[cc.length - 1].lex) - cc.pop()(); - if (style?.slice(0, 2) === "p5") return style; - if (cx.marked) return cx.marked; - if (type == "variable" && inScope(state, content)) return "variable-2"; - return style; - } - } - } - - // Combinator utils - - var cx = {state: null, column: null, marked: null, cc: null}; - function pass() { - for (var i = arguments.length - 1; i >= 0; i--) cx.cc.push(arguments[i]); - } - function cont() { - pass.apply(null, arguments); - return true; - } - function inList(name, list) { - for (var v = list; v; v = v.next) if (v.name == name) return true - return false; - } - function register(varname) { - var state = cx.state; - cx.marked = "def"; - if (state.context) { - if (state.lexical.info == "var" && state.context && state.context.block) { - // FIXME function decls are also not block scoped - var newContext = registerVarScoped(varname, state.context) - if (newContext != null) { - state.context = newContext - return + + function parseJS(state, style, type, content, stream) { + var cc = state.cc; + // Communicate our context to the combinators. + // (Less wasteful than consing up a hundred closures on every call.) + cx.state = state; + cx.stream = stream; + (cx.marked = null), (cx.cc = cc); + cx.style = style; + + if (!state.lexical.hasOwnProperty('align')) state.lexical.align = true; + + while (true) { + var combinator = cc.length + ? cc.pop() + : jsonMode + ? expression + : statement; + if (combinator(type, content)) { + while (cc.length && cc[cc.length - 1].lex) cc.pop()(); + if (style?.slice(0, 2) === 'p5') return style; + if (cx.marked) return cx.marked; + if (type == 'variable' && inScope(state, content)) + return 'variable-2'; + return style; } - } else if (!inList(varname, state.localVars)) { - state.localVars = new Var(varname, state.localVars) - return - } - } - window.register = register; - // Fall through means this is global - if (parserConfig.globalVars && !inList(varname, state.globalVars)) - state.globalVars = new Var(varname, state.globalVars) - } - function registerVarScoped(varname, context) { - if (!context) { - return null - } else if (context.block) { - var inner = registerVarScoped(varname, context.prev) - if (!inner) return null - if (inner == context.prev) return context - return new Context(inner, context.vars, true) - } else if (inList(varname, context.vars)) { - return context - } else { - return new Context(context.prev, new Var(varname, context.vars), false) - } - } - - function isModifier(name) { - return name == "public" || name == "private" || name == "protected" || name == "abstract" || name == "readonly" - } - - // Combinators - - function Context(prev, vars, block) { this.prev = prev; this.vars = vars; this.block = block } - function Var(name, next) { this.name = name; this.next = next } - - var defaultVars = new Var("this", new Var("arguments", null)) - function pushcontext() { - cx.state.context = new Context(cx.state.context, cx.state.localVars, false) - cx.state.localVars = defaultVars - } - function pushblockcontext() { - cx.state.context = new Context(cx.state.context, cx.state.localVars, true) - cx.state.localVars = null - } - function popcontext() { - cx.state.localVars = cx.state.context.vars - cx.state.context = cx.state.context.prev - } - popcontext.lex = true - function pushlex(type, info) { - var result = function() { - var state = cx.state, indent = state.indented; - if (state.lexical.type == "stat") indent = state.lexical.indented; - else for (var outer = state.lexical; outer && outer.type == ")" && outer.align; outer = outer.prev) - indent = outer.indented; - state.lexical = new JSLexical(indent, cx.stream.column(), type, null, state.lexical, info); - }; - result.lex = true; - return result; - } - function poplex() { - var state = cx.state; - if (state.lexical.prev) { - if (state.lexical.type == ")") - state.indented = state.lexical.indented; - state.lexical = state.lexical.prev; - } - } - poplex.lex = true; - - function expect(wanted) { - function exp(type) { - if (type == wanted) return cont(); - else if (wanted == ";" || type == "}" || type == ")" || type == "]") return pass(); - else return cont(exp); - }; - return exp; - } - - function statement(type, value) { - if (type == "var") return cont(pushlex("vardef", value), vardef, expect(";"), poplex); - if (type == "keyword a") return cont(pushlex("form"), parenExpr, statement, poplex); - if (type == "keyword b") return cont(pushlex("form"), statement, poplex); - if (type == "keyword d") return cx.stream.match(/^\s*$/, false) ? cont() : cont(pushlex("stat"), maybeexpression, expect(";"), poplex); - if (type == "debugger") return cont(expect(";")); - if (type == "{") return cont(pushlex("}"), pushblockcontext, block, poplex, popcontext); - if (type == ";") return cont(); - if (type == "if") { - if (cx.state.lexical.info == "else" && cx.state.cc[cx.state.cc.length - 1] == poplex) - cx.state.cc.pop()(); - return cont(pushlex("form"), parenExpr, statement, poplex, maybeelse); - } - if (type == "function") return cont(functiondef); - if (type == "for") return cont(pushlex("form"), forspec, statement, poplex); - if (type == "class" || (isTS && value == "interface")) { - cx.marked = "keyword" - return cont(pushlex("form", type == "class" ? type : value), className, poplex) - } - if (type == "variable") { - if (isTS && value == "declare") { - cx.marked = "keyword" - return cont(statement) - } else if (isTS && (value == "module" || value == "enum" || value == "type") && cx.stream.match(/^\s*\w/, false)) { - cx.marked = "keyword" - if (value == "enum") return cont(enumdef); - else if (value == "type") return cont(typeexpr, expect("operator"), typeexpr, expect(";")); - else return cont(pushlex("form"), pattern, expect("{"), pushlex("}"), block, poplex, poplex) - } else if (isTS && value == "namespace") { - cx.marked = "keyword" - return cont(pushlex("form"), expression, statement, poplex) - } else if (isTS && value == "abstract") { - cx.marked = "keyword" - return cont(statement) + } + } + + // Combinator utils + + var cx = { state: null, column: null, marked: null, cc: null }; + function pass() { + for (var i = arguments.length - 1; i >= 0; i--) cx.cc.push(arguments[i]); + } + function cont() { + pass.apply(null, arguments); + return true; + } + function inList(name, list) { + for (var v = list; v; v = v.next) if (v.name == name) return true; + return false; + } + function register(varname) { + var state = cx.state; + cx.marked = 'def'; + if (state.context) { + if ( + state.lexical.info == 'var' && + state.context && + state.context.block + ) { + // FIXME function decls are also not block scoped + var newContext = registerVarScoped(varname, state.context); + if (newContext != null) { + state.context = newContext; + return; + } + } else if (!inList(varname, state.localVars)) { + state.localVars = new Var(varname, state.localVars); + return; + } + } + window.register = register; + // Fall through means this is global + if (parserConfig.globalVars && !inList(varname, state.globalVars)) + state.globalVars = new Var(varname, state.globalVars); + } + function registerVarScoped(varname, context) { + if (!context) { + return null; + } else if (context.block) { + var inner = registerVarScoped(varname, context.prev); + if (!inner) return null; + if (inner == context.prev) return context; + return new Context(inner, context.vars, true); + } else if (inList(varname, context.vars)) { + return context; } else { - return cont(pushlex("stat"), maybelabel); - } - } - if (type == "switch") return cont(pushlex("form"), parenExpr, expect("{"), pushlex("}", "switch"), pushblockcontext, - block, poplex, poplex, popcontext); - if (type == "case") return cont(expression, expect(":")); - if (type == "default") return cont(expect(":")); - if (type == "catch") return cont(pushlex("form"), pushcontext, maybeCatchBinding, statement, poplex, popcontext); - if (type == "export") return cont(pushlex("stat"), afterExport, poplex); - if (type == "import") return cont(pushlex("stat"), afterImport, poplex); - if (type == "async") return cont(statement) - if (value == "@") return cont(expression, statement) - return pass(pushlex("stat"), expression, expect(";"), poplex); - } - function maybeCatchBinding(type) { - if (type == "(") return cont(funarg, expect(")")) - } - function expression(type, value) { - return expressionInner(type, value, false); - } - function expressionNoComma(type, value) { - return expressionInner(type, value, true); - } - function parenExpr(type) { - if (type != "(") return pass() - return cont(pushlex(")"), expression, expect(")"), poplex) - } - function expressionInner(type, value, noComma) { - if (cx.state.fatArrowAt == cx.stream.start) { - var body = noComma ? arrowBodyNoComma : arrowBody; - if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"), poplex, expect("=>"), body, popcontext); - else if (type == "variable") return pass(pushcontext, pattern, expect("=>"), body, popcontext); - } - - var maybeop = noComma ? maybeoperatorNoComma : maybeoperatorComma; - if (atomicTypes.hasOwnProperty(type)) return cont(maybeop); - if (type == "function") return cont(functiondef, maybeop); - if (type == "class" || (isTS && value == "interface")) { cx.marked = "keyword"; return cont(pushlex("form"), classExpression, poplex); } - if (type == "keyword c" || type == "async") return cont(noComma ? expressionNoComma : expression); - if (type == "(") return cont(pushlex(")"), maybeexpression, expect(")"), poplex, maybeop); - if (type == "operator" || type == "spread") return cont(noComma ? expressionNoComma : expression); - if (type == "[") return cont(pushlex("]"), arrayLiteral, poplex, maybeop); - if (type == "{") return contCommasep(objprop, "}", null, maybeop); - if (type == "quasi") return pass(quasi, maybeop); - if (type == "new") return cont(maybeTarget(noComma)); - if (type == "import") return cont(expression); - return cont(); - } - function maybeexpression(type) { - if (type.match(/[;\}\)\],]/)) return pass(); - return pass(expression); - } - - function maybeoperatorComma(type, value) { - if (type == ",") return cont(expression); - return maybeoperatorNoComma(type, value, false); - } - function maybeoperatorNoComma(type, value, noComma) { - var me = noComma == false ? maybeoperatorComma : maybeoperatorNoComma; - var expr = noComma == false ? expression : expressionNoComma; - if (type == "=>") return cont(pushcontext, noComma ? arrowBodyNoComma : arrowBody, popcontext); - if (type == "operator") { - if (/\+\+|--/.test(value) || isTS && value == "!") return cont(me); - if (isTS && value == "<" && cx.stream.match(/^([^>]|<.*?>)*>\s*\(/, false)) - return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, me); - if (value == "?") return cont(expression, expect(":"), expr); - return cont(expr); - } - if (type == "quasi") { return pass(quasi, me); } - if (type == ";") return; - if (type == "(") return contCommasep(expressionNoComma, ")", "call", me); - if (type == ".") return cont(property, me); - if (type == "[") return cont(pushlex("]"), maybeexpression, expect("]"), poplex, me); - if (isTS && value == "as") { cx.marked = "keyword"; return cont(typeexpr, me) } - if (type == "regexp") { - cx.state.lastType = cx.marked = "operator" - cx.stream.backUp(cx.stream.pos - cx.stream.start - 1) - return cont(expr) - } - } - function quasi(type, value) { - if (type != "quasi") return pass(); - if (value.slice(value.length - 2) != "${") return cont(quasi); - return cont(expression, continueQuasi); - } - function continueQuasi(type) { - if (type == "}") { - cx.marked = "string-2"; - cx.state.tokenize = tokenQuasi; - return cont(quasi); - } - } - function arrowBody(type) { - findFatArrow(cx.stream, cx.state); - return pass(type == "{" ? statement : expression); - } - function arrowBodyNoComma(type) { - findFatArrow(cx.stream, cx.state); - return pass(type == "{" ? statement : expressionNoComma); - } - function maybeTarget(noComma) { - return function(type) { - if (type == ".") return cont(noComma ? targetNoComma : target); - else if (type == "variable" && isTS) return cont(maybeTypeArgs, noComma ? maybeoperatorNoComma : maybeoperatorComma) - else return pass(noComma ? expressionNoComma : expression); - }; - } - function target(_, value) { - if (value == "target") { cx.marked = "keyword"; return cont(maybeoperatorComma); } - } - function targetNoComma(_, value) { - if (value == "target") { cx.marked = "keyword"; return cont(maybeoperatorNoComma); } - } - function maybelabel(type) { - if (type == ":") return cont(poplex, statement); - return pass(maybeoperatorComma, expect(";"), poplex); - } - function property(type) { - if (type == "variable") {cx.marked = "property"; return cont();} - } - function objprop(type, value) { - if (type == "async") { - cx.marked = "property"; - return cont(objprop); - } else if (type == "variable" || cx.style == "keyword") { - cx.marked = "property"; - if (value == "get" || value == "set") return cont(getterSetter); - var m // Work around fat-arrow-detection complication for detecting typescript typed arrow params - if (isTS && cx.state.fatArrowAt == cx.stream.start && (m = cx.stream.match(/^\s*:\s*/, false))) - cx.state.fatArrowAt = cx.stream.pos + m[0].length - return cont(afterprop); - } else if (type == "number" || type == "string") { - cx.marked = jsonldMode ? "property" : (cx.style + " property"); - return cont(afterprop); - } else if (type == "jsonld-keyword") { - return cont(afterprop); - } else if (isTS && isModifier(value)) { - cx.marked = "keyword" - return cont(objprop) - } else if (type == "[") { - return cont(expression, maybetype, expect("]"), afterprop); - } else if (type == "spread") { - return cont(expressionNoComma, afterprop); - } else if (value == "*") { - cx.marked = "keyword"; - return cont(objprop); - } else if (type == ":") { - return pass(afterprop) - } - } - function getterSetter(type) { - if (type != "variable") return pass(afterprop); - cx.marked = "property"; - return cont(functiondef); - } - function afterprop(type) { - if (type == ":") return cont(expressionNoComma); - if (type == "(") return pass(functiondef); - } - function commasep(what, end, sep) { - function proceed(type, value) { - if (sep ? sep.indexOf(type) > -1 : type == ",") { - var lex = cx.state.lexical; - if (lex.info == "call") lex.pos = (lex.pos || 0) + 1; - return cont(function(type, value) { - if (type == end || value == end) return pass() - return pass(what) - }, proceed); - } - if (type == end || value == end) return cont(); - if (sep && sep.indexOf(";") > -1) return pass(what) - return cont(expect(end)); - } - return function(type, value) { - if (type == end || value == end) return cont(); - return pass(what, proceed); - }; - } - function contCommasep(what, end, info) { - for (var i = 3; i < arguments.length; i++) - cx.cc.push(arguments[i]); - return cont(pushlex(end, info), commasep(what, end), poplex); - } - function block(type) { - if (type == "}") return cont(); - return pass(statement, block); - } - function maybetype(type, value) { - if (isTS) { - if (type == ":") return cont(typeexpr); - if (value == "?") return cont(maybetype); - } - } - function mayberettype(type) { - if (isTS && type == ":") { - if (cx.stream.match(/^\s*\w+\s+is\b/, false)) return cont(expression, isKW, typeexpr) - else return cont(typeexpr) - } - } - function isKW(_, value) { - if (value == "is") { - cx.marked = "keyword" - return cont() - } - } - function typeexpr(type, value) { - if (value == "keyof" || value == "typeof") { - cx.marked = "keyword" - return cont(value == "keyof" ? typeexpr : expressionNoComma) - } - if (type == "variable" || value == "void") { - cx.marked = "type" - return cont(afterType) - } - if (type == "string" || type == "number" || type == "atom") return cont(afterType); - if (type == "[") return cont(pushlex("]"), commasep(typeexpr, "]", ","), poplex, afterType) - if (type == "{") return cont(pushlex("}"), commasep(typeprop, "}", ",;"), poplex, afterType) - if (type == "(") return cont(commasep(typearg, ")"), maybeReturnType) - if (type == "<") return cont(commasep(typeexpr, ">"), typeexpr) - } - function maybeReturnType(type) { - if (type == "=>") return cont(typeexpr) - } - function typeprop(type, value) { - if (type == "variable" || cx.style == "keyword") { - cx.marked = "property" - return cont(typeprop) - } else if (value == "?") { - return cont(typeprop) - } else if (type == ":") { - return cont(typeexpr) - } else if (type == "[") { - return cont(expression, maybetype, expect("]"), typeprop) - } else if (type == "(") { - return cont(pushlex(")"), commasep(funarg, ")"), poplex, typeprop) - } - } - function typearg(type, value) { - if (type == "variable" && cx.stream.match(/^\s*[?:]/, false) || value == "?") return cont(typearg) - if (type == ":") return cont(typeexpr) - return pass(typeexpr) - } - function afterType(type, value) { - if (value == "<") return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, afterType) - if (value == "|" || type == "." || value == "&") return cont(typeexpr) - if (type == "[") return cont(expect("]"), afterType) - if (value == "extends" || value == "implements") { cx.marked = "keyword"; return cont(typeexpr) } - } - function maybeTypeArgs(_, value) { - if (value == "<") return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, afterType) - } - function typeparam() { - return pass(typeexpr, maybeTypeDefault) - } - function maybeTypeDefault(_, value) { - if (value == "=") return cont(typeexpr) - } - function vardef(_, value) { - if (value == "enum") {cx.marked = "keyword"; return cont(enumdef)} - return pass(pattern, maybetype, maybeAssign, vardefCont); - } - function pattern(type, value) { - if (isTS && isModifier(value)) { cx.marked = "keyword"; return cont(pattern) } - if (type == "variable") { register(value); return cont(); } - if (type == "spread") return cont(pattern); - if (type == "[") return contCommasep(eltpattern, "]"); - if (type == "{") return contCommasep(proppattern, "}"); - } - function proppattern(type, value) { - if (type == "variable" && !cx.stream.match(/^\s*:/, false)) { - register(value); - return cont(maybeAssign); - } - if (type == "variable") cx.marked = "property"; - if (type == "spread") return cont(pattern); - if (type == "}") return pass(); - if (type == "[") return cont(expression, expect(']'), expect(':'), proppattern); - return cont(expect(":"), pattern, maybeAssign); - } - function eltpattern() { - return pass(pattern, maybeAssign) - } - function maybeAssign(_type, value) { - if (value == "=") return cont(expressionNoComma); - } - function vardefCont(type) { - if (type == ",") return cont(vardef); - } - function maybeelse(type, value) { - if (type == "keyword b" && value == "else") return cont(pushlex("form", "else"), statement, poplex); - } - function forspec(type, value) { - if (value == "await") return cont(forspec); - if (type == "(") return cont(pushlex(")"), forspec1, expect(")"), poplex); - } - function forspec1(type) { - if (type == "var") return cont(vardef, expect(";"), forspec2); - if (type == ";") return cont(forspec2); - if (type == "variable") return cont(formaybeinof); - return pass(expression, expect(";"), forspec2); - } - function formaybeinof(_type, value) { - if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(expression); } - return cont(maybeoperatorComma, forspec2); - } - function forspec2(type, value) { - if (type == ";") return cont(forspec3); - if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(expression); } - return pass(expression, expect(";"), forspec3); - } - function forspec3(type) { - if (type != ")") cont(expression); - } - function functiondef(type, value) { - if (value == "*") {cx.marked = "keyword"; return cont(functiondef);} - if (type == "variable") {register(value); return cont(functiondef);} - if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"), poplex, mayberettype, statement, popcontext); - if (isTS && value == "<") return cont(pushlex(">"), commasep(typeparam, ">"), poplex, functiondef) - } - function functiondecl(type, value) { - if (value == "*") {cx.marked = "keyword"; return cont(functiondecl);} - if (type == "variable") {register(value); return cont(functiondecl);} - if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"), poplex, mayberettype, popcontext); - if (isTS && value == "<") return cont(pushlex(">"), commasep(typeparam, ">"), poplex, functiondecl) - } - function funarg(type, value) { - if (value == "@") cont(expression, funarg) - if (type == "spread") return cont(funarg); - if (isTS && isModifier(value)) { cx.marked = "keyword"; return cont(funarg); } - return pass(pattern, maybetype, maybeAssign); - } - function classExpression(type, value) { - // Class expressions may have an optional name. - if (type == "variable") return className(type, value); - return classNameAfter(type, value); - } - function className(type, value) { - if (type == "variable") {register(value); return cont(classNameAfter);} - } - function classNameAfter(type, value) { - if (value == "<") return cont(pushlex(">"), commasep(typeparam, ">"), poplex, classNameAfter) - if (value == "extends" || value == "implements" || (isTS && type == ",")) { - if (value == "implements") cx.marked = "keyword"; - return cont(isTS ? typeexpr : expression, classNameAfter); - } - if (type == "{") return cont(pushlex("}"), classBody, poplex); - } - function classBody(type, value) { - if (type == "async" || - (type == "variable" && - (value == "static" || value == "get" || value == "set" || (isTS && isModifier(value))) && - cx.stream.match(/^\s+[\w$\xa1-\uffff]/, false))) { - cx.marked = "keyword"; - return cont(classBody); - } - if (type == "variable" || cx.style == "keyword") { - cx.marked = "property"; - return cont(isTS ? classfield : functiondef, classBody); - } - if (type == "[") - return cont(expression, maybetype, expect("]"), isTS ? classfield : functiondef, classBody) - if (value == "*") { - cx.marked = "keyword"; - return cont(classBody); - } - if (type == ";") return cont(classBody); - if (type == "}") return cont(); - if (value == "@") return cont(expression, classBody) - } - function classfield(type, value) { - if (value == "?") return cont(classfield) - if (type == ":") return cont(typeexpr, maybeAssign) - if (value == "=") return cont(expressionNoComma) - var context = cx.state.lexical.prev, isInterface = context && context.info == "interface" - return pass(isInterface ? functiondecl : functiondef) - } - function afterExport(type, value) { - if (value == "*") { cx.marked = "keyword"; return cont(maybeFrom, expect(";")); } - if (value == "default") { cx.marked = "keyword"; return cont(expression, expect(";")); } - if (type == "{") return cont(commasep(exportField, "}"), maybeFrom, expect(";")); - return pass(statement); - } - function exportField(type, value) { - if (value == "as") { cx.marked = "keyword"; return cont(expect("variable")); } - if (type == "variable") return pass(expressionNoComma, exportField); - } - function afterImport(type) { - if (type == "string") return cont(); - if (type == "(") return pass(expression); - return pass(importSpec, maybeMoreImports, maybeFrom); - } - function importSpec(type, value) { - if (type == "{") return contCommasep(importSpec, "}"); - if (type == "variable") register(value); - if (value == "*") cx.marked = "keyword"; - return cont(maybeAs); - } - function maybeMoreImports(type) { - if (type == ",") return cont(importSpec, maybeMoreImports) - } - function maybeAs(_type, value) { - if (value == "as") { cx.marked = "keyword"; return cont(importSpec); } - } - function maybeFrom(_type, value) { - if (value == "from") { cx.marked = "keyword"; return cont(expression); } - } - function arrayLiteral(type) { - if (type == "]") return cont(); - return pass(commasep(expressionNoComma, "]")); - } - function enumdef() { - return pass(pushlex("form"), pattern, expect("{"), pushlex("}"), commasep(enummember, "}"), poplex, poplex) - } - function enummember() { - return pass(pattern, maybeAssign); - } - - function isContinuedStatement(state, textAfter) { - return state.lastType == "operator" || state.lastType == "," || - isOperatorChar.test(textAfter.charAt(0)) || - /[,.]/.test(textAfter.charAt(0)); - } - - function expressionAllowed(stream, state, backUp) { - return state.tokenize == tokenBase && - /^(?:operator|sof|keyword [bcd]|case|new|export|default|spread|[\[{}\(,;:]|=>)$/.test(state.lastType) || - (state.lastType == "quasi" && /\{\s*$/.test(stream.string.slice(0, stream.pos - (backUp || 0)))) - } - - // Interface - - return { - startState: function(basecolumn) { - var state = { - tokenize: tokenBase, - lastType: "sof", - cc: [], - lexical: new JSLexical((basecolumn || 0) - indentUnit, 0, "block", false), - localVars: parserConfig.localVars, - context: parserConfig.localVars && new Context(null, null, false), - indented: basecolumn || 0 + return new Context(context.prev, new Var(varname, context.vars), false); + } + } + + function isModifier(name) { + return ( + name == 'public' || + name == 'private' || + name == 'protected' || + name == 'abstract' || + name == 'readonly' + ); + } + + // Combinators + + function Context(prev, vars, block) { + this.prev = prev; + this.vars = vars; + this.block = block; + } + function Var(name, next) { + this.name = name; + this.next = next; + } + + var defaultVars = new Var('this', new Var('arguments', null)); + function pushcontext() { + cx.state.context = new Context( + cx.state.context, + cx.state.localVars, + false + ); + cx.state.localVars = defaultVars; + } + function pushblockcontext() { + cx.state.context = new Context( + cx.state.context, + cx.state.localVars, + true + ); + cx.state.localVars = null; + } + function popcontext() { + cx.state.localVars = cx.state.context.vars; + cx.state.context = cx.state.context.prev; + } + popcontext.lex = true; + function pushlex(type, info) { + var result = function () { + var state = cx.state, + indent = state.indented; + if (state.lexical.type == 'stat') indent = state.lexical.indented; + else + for ( + var outer = state.lexical; + outer && outer.type == ')' && outer.align; + outer = outer.prev + ) + indent = outer.indented; + state.lexical = new JSLexical( + indent, + cx.stream.column(), + type, + null, + state.lexical, + info + ); }; - if (parserConfig.globalVars && typeof parserConfig.globalVars == "object") - state.globalVars = parserConfig.globalVars; - return state; - }, - - token: function(stream, state) { - if (stream.sol()) { - if (!state.lexical.hasOwnProperty("align")) - state.lexical.align = false; - state.indented = stream.indentation(); - findFatArrow(stream, state); - } - if (state.tokenize != tokenComment && stream.eatSpace()) return null; - var style = state.tokenize(stream, state); - if (type == "comment") return style; - state.lastType = type == "operator" && (content == "++" || content == "--") ? "incdec" : type; - return parseJS(state, style, type, content, stream); - }, - - indent: function(state, textAfter) { - if (state.tokenize == tokenComment) return CodeMirror.Pass; - if (state.tokenize != tokenBase) return 0; - var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical, top - // Kludge to prevent 'maybelse' from blocking lexical scope pops - if (!/^\s*else\b/.test(textAfter)) for (var i = state.cc.length - 1; i >= 0; --i) { - var c = state.cc[i]; - if (c == poplex) lexical = lexical.prev; - else if (c != maybeelse) break; - } - while ((lexical.type == "stat" || lexical.type == "form") && - (firstChar == "}" || ((top = state.cc[state.cc.length - 1]) && - (top == maybeoperatorComma || top == maybeoperatorNoComma) && - !/^[,\.=+\-*:?[\(]/.test(textAfter)))) - lexical = lexical.prev; - if (statementIndent && lexical.type == ")" && lexical.prev.type == "stat") - lexical = lexical.prev; - var type = lexical.type, closing = firstChar == type; - - if (type == "vardef") return lexical.indented + (state.lastType == "operator" || state.lastType == "," ? lexical.info.length + 1 : 0); - else if (type == "form" && firstChar == "{") return lexical.indented; - else if (type == "form") return lexical.indented + indentUnit; - else if (type == "stat") - return lexical.indented + (isContinuedStatement(state, textAfter) ? statementIndent || indentUnit : 0); - else if (lexical.info == "switch" && !closing && parserConfig.doubleIndentSwitch != false) - return lexical.indented + (/^(?:case|default)\b/.test(textAfter) ? indentUnit : 2 * indentUnit); - else if (lexical.align) return lexical.column + (closing ? 0 : 1); - else return lexical.indented + (closing ? 0 : indentUnit); - }, - - electricInput: /^\s*(?:case .*?:|default:|\{|\})$/, - blockCommentStart: jsonMode ? null : "/*", - blockCommentEnd: jsonMode ? null : "*/", - blockCommentContinue: jsonMode ? null : " * ", - lineComment: jsonMode ? null : "//", - fold: "brace", - closeBrackets: "()[]{}''\"\"``", - - helperType: jsonMode ? "json" : "javascript", - jsonldMode: jsonldMode, - jsonMode: jsonMode, - - expressionAllowed: expressionAllowed, - - skipExpression: function(state) { - var top = state.cc[state.cc.length - 1] - if (top == expression || top == expressionNoComma) state.cc.pop() - } - }; -}); + result.lex = true; + return result; + } + function poplex() { + var state = cx.state; + if (state.lexical.prev) { + if (state.lexical.type == ')') state.indented = state.lexical.indented; + state.lexical = state.lexical.prev; + } + } + poplex.lex = true; -CodeMirror.registerHelper("wordChars", "javascript", /[\w$]/); + function expect(wanted) { + function exp(type) { + if (type == wanted) return cont(); + else if (wanted == ';' || type == '}' || type == ')' || type == ']') + return pass(); + else return cont(exp); + } + return exp; + } + + function statement(type, value) { + if (type == 'var') + return cont(pushlex('vardef', value), vardef, expect(';'), poplex); + if (type == 'keyword a') + return cont(pushlex('form'), parenExpr, statement, poplex); + if (type == 'keyword b') return cont(pushlex('form'), statement, poplex); + if (type == 'keyword d') + return cx.stream.match(/^\s*$/, false) + ? cont() + : cont(pushlex('stat'), maybeexpression, expect(';'), poplex); + if (type == 'debugger') return cont(expect(';')); + if (type == '{') + return cont(pushlex('}'), pushblockcontext, block, poplex, popcontext); + if (type == ';') return cont(); + if (type == 'if') { + if ( + cx.state.lexical.info == 'else' && + cx.state.cc[cx.state.cc.length - 1] == poplex + ) + cx.state.cc.pop()(); + return cont(pushlex('form'), parenExpr, statement, poplex, maybeelse); + } + if (type == 'function') return cont(functiondef); + if (type == 'for') + return cont(pushlex('form'), forspec, statement, poplex); + if (type == 'class' || (isTS && value == 'interface')) { + cx.marked = 'keyword'; + return cont( + pushlex('form', type == 'class' ? type : value), + className, + poplex + ); + } + if (type == 'variable') { + if (isTS && value == 'declare') { + cx.marked = 'keyword'; + return cont(statement); + } else if ( + isTS && + (value == 'module' || value == 'enum' || value == 'type') && + cx.stream.match(/^\s*\w/, false) + ) { + cx.marked = 'keyword'; + if (value == 'enum') return cont(enumdef); + else if (value == 'type') + return cont(typeexpr, expect('operator'), typeexpr, expect(';')); + else + return cont( + pushlex('form'), + pattern, + expect('{'), + pushlex('}'), + block, + poplex, + poplex + ); + } else if (isTS && value == 'namespace') { + cx.marked = 'keyword'; + return cont(pushlex('form'), expression, statement, poplex); + } else if (isTS && value == 'abstract') { + cx.marked = 'keyword'; + return cont(statement); + } else { + return cont(pushlex('stat'), maybelabel); + } + } + if (type == 'switch') + return cont( + pushlex('form'), + parenExpr, + expect('{'), + pushlex('}', 'switch'), + pushblockcontext, + block, + poplex, + poplex, + popcontext + ); + if (type == 'case') return cont(expression, expect(':')); + if (type == 'default') return cont(expect(':')); + if (type == 'catch') + return cont( + pushlex('form'), + pushcontext, + maybeCatchBinding, + statement, + poplex, + popcontext + ); + if (type == 'export') return cont(pushlex('stat'), afterExport, poplex); + if (type == 'import') return cont(pushlex('stat'), afterImport, poplex); + if (type == 'async') return cont(statement); + if (value == '@') return cont(expression, statement); + return pass(pushlex('stat'), expression, expect(';'), poplex); + } + function maybeCatchBinding(type) { + if (type == '(') return cont(funarg, expect(')')); + } + function expression(type, value) { + return expressionInner(type, value, false); + } + function expressionNoComma(type, value) { + return expressionInner(type, value, true); + } + function parenExpr(type) { + if (type != '(') return pass(); + return cont(pushlex(')'), expression, expect(')'), poplex); + } + function expressionInner(type, value, noComma) { + if (cx.state.fatArrowAt == cx.stream.start) { + var body = noComma ? arrowBodyNoComma : arrowBody; + if (type == '(') + return cont( + pushcontext, + pushlex(')'), + commasep(funarg, ')'), + poplex, + expect('=>'), + body, + popcontext + ); + else if (type == 'variable') + return pass(pushcontext, pattern, expect('=>'), body, popcontext); + } + + var maybeop = noComma ? maybeoperatorNoComma : maybeoperatorComma; + if (atomicTypes.hasOwnProperty(type)) return cont(maybeop); + if (type == 'function') return cont(functiondef, maybeop); + if (type == 'class' || (isTS && value == 'interface')) { + cx.marked = 'keyword'; + return cont(pushlex('form'), classExpression, poplex); + } + if (type == 'keyword c' || type == 'async') + return cont(noComma ? expressionNoComma : expression); + if (type == '(') + return cont( + pushlex(')'), + maybeexpression, + expect(')'), + poplex, + maybeop + ); + if (type == 'operator' || type == 'spread') + return cont(noComma ? expressionNoComma : expression); + if (type == '[') return cont(pushlex(']'), arrayLiteral, poplex, maybeop); + if (type == '{') return contCommasep(objprop, '}', null, maybeop); + if (type == 'quasi') return pass(quasi, maybeop); + if (type == 'new') return cont(maybeTarget(noComma)); + if (type == 'import') return cont(expression); + return cont(); + } + function maybeexpression(type) { + if (type.match(/[;\}\)\],]/)) return pass(); + return pass(expression); + } + + function maybeoperatorComma(type, value) { + if (type == ',') return cont(expression); + return maybeoperatorNoComma(type, value, false); + } + function maybeoperatorNoComma(type, value, noComma) { + var me = noComma == false ? maybeoperatorComma : maybeoperatorNoComma; + var expr = noComma == false ? expression : expressionNoComma; + if (type == '=>') + return cont( + pushcontext, + noComma ? arrowBodyNoComma : arrowBody, + popcontext + ); + if (type == 'operator') { + if (/\+\+|--/.test(value) || (isTS && value == '!')) return cont(me); + if ( + isTS && + value == '<' && + cx.stream.match(/^([^>]|<.*?>)*>\s*\(/, false) + ) + return cont(pushlex('>'), commasep(typeexpr, '>'), poplex, me); + if (value == '?') return cont(expression, expect(':'), expr); + return cont(expr); + } + if (type == 'quasi') { + return pass(quasi, me); + } + if (type == ';') return; + if (type == '(') return contCommasep(expressionNoComma, ')', 'call', me); + if (type == '.') return cont(property, me); + if (type == '[') + return cont(pushlex(']'), maybeexpression, expect(']'), poplex, me); + if (isTS && value == 'as') { + cx.marked = 'keyword'; + return cont(typeexpr, me); + } + if (type == 'regexp') { + cx.state.lastType = cx.marked = 'operator'; + cx.stream.backUp(cx.stream.pos - cx.stream.start - 1); + return cont(expr); + } + } + function quasi(type, value) { + if (type != 'quasi') return pass(); + if (value.slice(value.length - 2) != '${') return cont(quasi); + return cont(expression, continueQuasi); + } + function continueQuasi(type) { + if (type == '}') { + cx.marked = 'string-2'; + cx.state.tokenize = tokenQuasi; + return cont(quasi); + } + } + function arrowBody(type) { + findFatArrow(cx.stream, cx.state); + return pass(type == '{' ? statement : expression); + } + function arrowBodyNoComma(type) { + findFatArrow(cx.stream, cx.state); + return pass(type == '{' ? statement : expressionNoComma); + } + function maybeTarget(noComma) { + return function (type) { + if (type == '.') return cont(noComma ? targetNoComma : target); + else if (type == 'variable' && isTS) + return cont( + maybeTypeArgs, + noComma ? maybeoperatorNoComma : maybeoperatorComma + ); + else return pass(noComma ? expressionNoComma : expression); + }; + } + function target(_, value) { + if (value == 'target') { + cx.marked = 'keyword'; + return cont(maybeoperatorComma); + } + } + function targetNoComma(_, value) { + if (value == 'target') { + cx.marked = 'keyword'; + return cont(maybeoperatorNoComma); + } + } + function maybelabel(type) { + if (type == ':') return cont(poplex, statement); + return pass(maybeoperatorComma, expect(';'), poplex); + } + function property(type) { + if (type == 'variable') { + cx.marked = 'property'; + return cont(); + } + } + function objprop(type, value) { + if (type == 'async') { + cx.marked = 'property'; + return cont(objprop); + } else if (type == 'variable' || cx.style == 'keyword') { + cx.marked = 'property'; + if (value == 'get' || value == 'set') return cont(getterSetter); + var m; // Work around fat-arrow-detection complication for detecting typescript typed arrow params + if ( + isTS && + cx.state.fatArrowAt == cx.stream.start && + (m = cx.stream.match(/^\s*:\s*/, false)) + ) + cx.state.fatArrowAt = cx.stream.pos + m[0].length; + return cont(afterprop); + } else if (type == 'number' || type == 'string') { + cx.marked = jsonldMode ? 'property' : cx.style + ' property'; + return cont(afterprop); + } else if (type == 'jsonld-keyword') { + return cont(afterprop); + } else if (isTS && isModifier(value)) { + cx.marked = 'keyword'; + return cont(objprop); + } else if (type == '[') { + return cont(expression, maybetype, expect(']'), afterprop); + } else if (type == 'spread') { + return cont(expressionNoComma, afterprop); + } else if (value == '*') { + cx.marked = 'keyword'; + return cont(objprop); + } else if (type == ':') { + return pass(afterprop); + } + } + function getterSetter(type) { + if (type != 'variable') return pass(afterprop); + cx.marked = 'property'; + return cont(functiondef); + } + function afterprop(type) { + if (type == ':') return cont(expressionNoComma); + if (type == '(') return pass(functiondef); + } + function commasep(what, end, sep) { + function proceed(type, value) { + if (sep ? sep.indexOf(type) > -1 : type == ',') { + var lex = cx.state.lexical; + if (lex.info == 'call') lex.pos = (lex.pos || 0) + 1; + return cont(function (type, value) { + if (type == end || value == end) return pass(); + return pass(what); + }, proceed); + } + if (type == end || value == end) return cont(); + if (sep && sep.indexOf(';') > -1) return pass(what); + return cont(expect(end)); + } + return function (type, value) { + if (type == end || value == end) return cont(); + return pass(what, proceed); + }; + } + function contCommasep(what, end, info) { + for (var i = 3; i < arguments.length; i++) cx.cc.push(arguments[i]); + return cont(pushlex(end, info), commasep(what, end), poplex); + } + function block(type) { + if (type == '}') return cont(); + return pass(statement, block); + } + function maybetype(type, value) { + if (isTS) { + if (type == ':') return cont(typeexpr); + if (value == '?') return cont(maybetype); + } + } + function mayberettype(type) { + if (isTS && type == ':') { + if (cx.stream.match(/^\s*\w+\s+is\b/, false)) + return cont(expression, isKW, typeexpr); + else return cont(typeexpr); + } + } + function isKW(_, value) { + if (value == 'is') { + cx.marked = 'keyword'; + return cont(); + } + } + function typeexpr(type, value) { + if (value == 'keyof' || value == 'typeof') { + cx.marked = 'keyword'; + return cont(value == 'keyof' ? typeexpr : expressionNoComma); + } + if (type == 'variable' || value == 'void') { + cx.marked = 'type'; + return cont(afterType); + } + if (type == 'string' || type == 'number' || type == 'atom') + return cont(afterType); + if (type == '[') + return cont( + pushlex(']'), + commasep(typeexpr, ']', ','), + poplex, + afterType + ); + if (type == '{') + return cont( + pushlex('}'), + commasep(typeprop, '}', ',;'), + poplex, + afterType + ); + if (type == '(') return cont(commasep(typearg, ')'), maybeReturnType); + if (type == '<') return cont(commasep(typeexpr, '>'), typeexpr); + } + function maybeReturnType(type) { + if (type == '=>') return cont(typeexpr); + } + function typeprop(type, value) { + if (type == 'variable' || cx.style == 'keyword') { + cx.marked = 'property'; + return cont(typeprop); + } else if (value == '?') { + return cont(typeprop); + } else if (type == ':') { + return cont(typeexpr); + } else if (type == '[') { + return cont(expression, maybetype, expect(']'), typeprop); + } else if (type == '(') { + return cont(pushlex(')'), commasep(funarg, ')'), poplex, typeprop); + } + } + function typearg(type, value) { + if ( + (type == 'variable' && cx.stream.match(/^\s*[?:]/, false)) || + value == '?' + ) + return cont(typearg); + if (type == ':') return cont(typeexpr); + return pass(typeexpr); + } + function afterType(type, value) { + if (value == '<') + return cont(pushlex('>'), commasep(typeexpr, '>'), poplex, afterType); + if (value == '|' || type == '.' || value == '&') return cont(typeexpr); + if (type == '[') return cont(expect(']'), afterType); + if (value == 'extends' || value == 'implements') { + cx.marked = 'keyword'; + return cont(typeexpr); + } + } + function maybeTypeArgs(_, value) { + if (value == '<') + return cont(pushlex('>'), commasep(typeexpr, '>'), poplex, afterType); + } + function typeparam() { + return pass(typeexpr, maybeTypeDefault); + } + function maybeTypeDefault(_, value) { + if (value == '=') return cont(typeexpr); + } + function vardef(_, value) { + if (value == 'enum') { + cx.marked = 'keyword'; + return cont(enumdef); + } + return pass(pattern, maybetype, maybeAssign, vardefCont); + } + function pattern(type, value) { + if (isTS && isModifier(value)) { + cx.marked = 'keyword'; + return cont(pattern); + } + if (type == 'variable') { + register(value); + return cont(); + } + if (type == 'spread') return cont(pattern); + if (type == '[') return contCommasep(eltpattern, ']'); + if (type == '{') return contCommasep(proppattern, '}'); + } + function proppattern(type, value) { + if (type == 'variable' && !cx.stream.match(/^\s*:/, false)) { + register(value); + return cont(maybeAssign); + } + if (type == 'variable') cx.marked = 'property'; + if (type == 'spread') return cont(pattern); + if (type == '}') return pass(); + if (type == '[') + return cont(expression, expect(']'), expect(':'), proppattern); + return cont(expect(':'), pattern, maybeAssign); + } + function eltpattern() { + return pass(pattern, maybeAssign); + } + function maybeAssign(_type, value) { + if (value == '=') return cont(expressionNoComma); + } + function vardefCont(type) { + if (type == ',') return cont(vardef); + } + function maybeelse(type, value) { + if (type == 'keyword b' && value == 'else') + return cont(pushlex('form', 'else'), statement, poplex); + } + function forspec(type, value) { + if (value == 'await') return cont(forspec); + if (type == '(') return cont(pushlex(')'), forspec1, expect(')'), poplex); + } + function forspec1(type) { + if (type == 'var') return cont(vardef, expect(';'), forspec2); + if (type == ';') return cont(forspec2); + if (type == 'variable') return cont(formaybeinof); + return pass(expression, expect(';'), forspec2); + } + function formaybeinof(_type, value) { + if (value == 'in' || value == 'of') { + cx.marked = 'keyword'; + return cont(expression); + } + return cont(maybeoperatorComma, forspec2); + } + function forspec2(type, value) { + if (type == ';') return cont(forspec3); + if (value == 'in' || value == 'of') { + cx.marked = 'keyword'; + return cont(expression); + } + return pass(expression, expect(';'), forspec3); + } + function forspec3(type) { + if (type != ')') cont(expression); + } + function functiondef(type, value) { + if (value == '*') { + cx.marked = 'keyword'; + return cont(functiondef); + } + if (type == 'variable') { + register(value); + return cont(functiondef); + } + if (type == '(') + return cont( + pushcontext, + pushlex(')'), + commasep(funarg, ')'), + poplex, + mayberettype, + statement, + popcontext + ); + if (isTS && value == '<') + return cont( + pushlex('>'), + commasep(typeparam, '>'), + poplex, + functiondef + ); + } + function functiondecl(type, value) { + if (value == '*') { + cx.marked = 'keyword'; + return cont(functiondecl); + } + if (type == 'variable') { + register(value); + return cont(functiondecl); + } + if (type == '(') + return cont( + pushcontext, + pushlex(')'), + commasep(funarg, ')'), + poplex, + mayberettype, + popcontext + ); + if (isTS && value == '<') + return cont( + pushlex('>'), + commasep(typeparam, '>'), + poplex, + functiondecl + ); + } + function funarg(type, value) { + if (value == '@') cont(expression, funarg); + if (type == 'spread') return cont(funarg); + if (isTS && isModifier(value)) { + cx.marked = 'keyword'; + return cont(funarg); + } + return pass(pattern, maybetype, maybeAssign); + } + function classExpression(type, value) { + // Class expressions may have an optional name. + if (type == 'variable') return className(type, value); + return classNameAfter(type, value); + } + function className(type, value) { + if (type == 'variable') { + register(value); + return cont(classNameAfter); + } + } + function classNameAfter(type, value) { + if (value == '<') + return cont( + pushlex('>'), + commasep(typeparam, '>'), + poplex, + classNameAfter + ); + if ( + value == 'extends' || + value == 'implements' || + (isTS && type == ',') + ) { + if (value == 'implements') cx.marked = 'keyword'; + return cont(isTS ? typeexpr : expression, classNameAfter); + } + if (type == '{') return cont(pushlex('}'), classBody, poplex); + } + function classBody(type, value) { + if ( + type == 'async' || + (type == 'variable' && + (value == 'static' || + value == 'get' || + value == 'set' || + (isTS && isModifier(value))) && + cx.stream.match(/^\s+[\w$\xa1-\uffff]/, false)) + ) { + cx.marked = 'keyword'; + return cont(classBody); + } + if (type == 'variable' || cx.style == 'keyword') { + cx.marked = 'property'; + return cont(isTS ? classfield : functiondef, classBody); + } + if (type == '[') + return cont( + expression, + maybetype, + expect(']'), + isTS ? classfield : functiondef, + classBody + ); + if (value == '*') { + cx.marked = 'keyword'; + return cont(classBody); + } + if (type == ';') return cont(classBody); + if (type == '}') return cont(); + if (value == '@') return cont(expression, classBody); + } + function classfield(type, value) { + if (value == '?') return cont(classfield); + if (type == ':') return cont(typeexpr, maybeAssign); + if (value == '=') return cont(expressionNoComma); + var context = cx.state.lexical.prev, + isInterface = context && context.info == 'interface'; + return pass(isInterface ? functiondecl : functiondef); + } + function afterExport(type, value) { + if (value == '*') { + cx.marked = 'keyword'; + return cont(maybeFrom, expect(';')); + } + if (value == 'default') { + cx.marked = 'keyword'; + return cont(expression, expect(';')); + } + if (type == '{') + return cont(commasep(exportField, '}'), maybeFrom, expect(';')); + return pass(statement); + } + function exportField(type, value) { + if (value == 'as') { + cx.marked = 'keyword'; + return cont(expect('variable')); + } + if (type == 'variable') return pass(expressionNoComma, exportField); + } + function afterImport(type) { + if (type == 'string') return cont(); + if (type == '(') return pass(expression); + return pass(importSpec, maybeMoreImports, maybeFrom); + } + function importSpec(type, value) { + if (type == '{') return contCommasep(importSpec, '}'); + if (type == 'variable') register(value); + if (value == '*') cx.marked = 'keyword'; + return cont(maybeAs); + } + function maybeMoreImports(type) { + if (type == ',') return cont(importSpec, maybeMoreImports); + } + function maybeAs(_type, value) { + if (value == 'as') { + cx.marked = 'keyword'; + return cont(importSpec); + } + } + function maybeFrom(_type, value) { + if (value == 'from') { + cx.marked = 'keyword'; + return cont(expression); + } + } + function arrayLiteral(type) { + if (type == ']') return cont(); + return pass(commasep(expressionNoComma, ']')); + } + function enumdef() { + return pass( + pushlex('form'), + pattern, + expect('{'), + pushlex('}'), + commasep(enummember, '}'), + poplex, + poplex + ); + } + function enummember() { + return pass(pattern, maybeAssign); + } + + function isContinuedStatement(state, textAfter) { + return ( + state.lastType == 'operator' || + state.lastType == ',' || + isOperatorChar.test(textAfter.charAt(0)) || + /[,.]/.test(textAfter.charAt(0)) + ); + } + + function expressionAllowed(stream, state, backUp) { + return ( + (state.tokenize == tokenBase && + /^(?:operator|sof|keyword [bcd]|case|new|export|default|spread|[\[{}\(,;:]|=>)$/.test( + state.lastType + )) || + (state.lastType == 'quasi' && + /\{\s*$/.test(stream.string.slice(0, stream.pos - (backUp || 0)))) + ); + } + + // Interface + + return { + startState: function (basecolumn) { + var state = { + tokenize: tokenBase, + lastType: 'sof', + cc: [], + lexical: new JSLexical( + (basecolumn || 0) - indentUnit, + 0, + 'block', + false + ), + localVars: parserConfig.localVars, + context: parserConfig.localVars && new Context(null, null, false), + indented: basecolumn || 0 + }; + if ( + parserConfig.globalVars && + typeof parserConfig.globalVars == 'object' + ) + state.globalVars = parserConfig.globalVars; + return state; + }, + + token: function (stream, state) { + if (stream.sol()) { + if (!state.lexical.hasOwnProperty('align')) + state.lexical.align = false; + state.indented = stream.indentation(); + findFatArrow(stream, state); + } + if (state.tokenize != tokenComment && stream.eatSpace()) return null; + var style = state.tokenize(stream, state); + if (type == 'comment') return style; + state.lastType = + type == 'operator' && (content == '++' || content == '--') + ? 'incdec' + : type; + return parseJS(state, style, type, content, stream); + }, + + indent: function (state, textAfter) { + if (state.tokenize == tokenComment) return CodeMirror.Pass; + if (state.tokenize != tokenBase) return 0; + var firstChar = textAfter && textAfter.charAt(0), + lexical = state.lexical, + top; + // Kludge to prevent 'maybelse' from blocking lexical scope pops + if (!/^\s*else\b/.test(textAfter)) + for (var i = state.cc.length - 1; i >= 0; --i) { + var c = state.cc[i]; + if (c == poplex) lexical = lexical.prev; + else if (c != maybeelse) break; + } + while ( + (lexical.type == 'stat' || lexical.type == 'form') && + (firstChar == '}' || + ((top = state.cc[state.cc.length - 1]) && + (top == maybeoperatorComma || top == maybeoperatorNoComma) && + !/^[,\.=+\-*:?[\(]/.test(textAfter))) + ) + lexical = lexical.prev; + if ( + statementIndent && + lexical.type == ')' && + lexical.prev.type == 'stat' + ) + lexical = lexical.prev; + var type = lexical.type, + closing = firstChar == type; + + if (type == 'vardef') + return ( + lexical.indented + + (state.lastType == 'operator' || state.lastType == ',' + ? lexical.info.length + 1 + : 0) + ); + else if (type == 'form' && firstChar == '{') return lexical.indented; + else if (type == 'form') return lexical.indented + indentUnit; + else if (type == 'stat') + return ( + lexical.indented + + (isContinuedStatement(state, textAfter) + ? statementIndent || indentUnit + : 0) + ); + else if ( + lexical.info == 'switch' && + !closing && + parserConfig.doubleIndentSwitch != false + ) + return ( + lexical.indented + + (/^(?:case|default)\b/.test(textAfter) + ? indentUnit + : 2 * indentUnit) + ); + else if (lexical.align) return lexical.column + (closing ? 0 : 1); + else return lexical.indented + (closing ? 0 : indentUnit); + }, + + electricInput: /^\s*(?:case .*?:|default:|\{|\})$/, + blockCommentStart: jsonMode ? null : '/*', + blockCommentEnd: jsonMode ? null : '*/', + blockCommentContinue: jsonMode ? null : ' * ', + lineComment: jsonMode ? null : '//', + fold: 'brace', + closeBrackets: '()[]{}\'\'""``', + + helperType: jsonMode ? 'json' : 'javascript', + jsonldMode: jsonldMode, + jsonMode: jsonMode, + + expressionAllowed: expressionAllowed, + + skipExpression: function (state) { + var top = state.cc[state.cc.length - 1]; + if (top == expression || top == expressionNoComma) state.cc.pop(); + } + }; + }); -CodeMirror.defineMIME("text/javascript", "javascript"); -CodeMirror.defineMIME("text/ecmascript", "javascript"); -CodeMirror.defineMIME("application/javascript", "javascript"); -CodeMirror.defineMIME("application/x-javascript", "javascript"); -CodeMirror.defineMIME("application/ecmascript", "javascript"); -CodeMirror.defineMIME("application/json", {name: "javascript", json: true}); -CodeMirror.defineMIME("application/x-json", {name: "javascript", json: true}); -CodeMirror.defineMIME("application/ld+json", {name: "javascript", jsonld: true}); -CodeMirror.defineMIME("text/typescript", { name: "javascript", typescript: true }); -CodeMirror.defineMIME("application/typescript", { name: "javascript", typescript: true }); + CodeMirror.registerHelper('wordChars', 'javascript', /[\w$]/); + CodeMirror.defineMIME('text/javascript', 'javascript'); + CodeMirror.defineMIME('text/ecmascript', 'javascript'); + CodeMirror.defineMIME('application/javascript', 'javascript'); + CodeMirror.defineMIME('application/x-javascript', 'javascript'); + CodeMirror.defineMIME('application/ecmascript', 'javascript'); + CodeMirror.defineMIME('application/json', { name: 'javascript', json: true }); + CodeMirror.defineMIME('application/x-json', { + name: 'javascript', + json: true + }); + CodeMirror.defineMIME('application/ld+json', { + name: 'javascript', + jsonld: true + }); + CodeMirror.defineMIME('text/typescript', { + name: 'javascript', + typescript: true + }); + CodeMirror.defineMIME('application/typescript', { + name: 'javascript', + typescript: true + }); }); diff --git a/client/utils/p5-keywords.js b/client/utils/p5-keywords.js index 6408051d01..9a41ccc099 100644 --- a/client/utils/p5-keywords.js +++ b/client/utils/p5-keywords.js @@ -1,8 +1,494 @@ -/* eslint-disable */ -/* generated: do not edit! helper file for syntax highlighting. generated by update-syntax-highlighting script */ -var p5Function = {type: "variable", style: "p5-function"}; -var p5Variable = {type: "variable", style: "p5-variable"}; -let p5VariableKeywords = {"VERSION":p5Variable,"P2D":p5Variable,"WEBGL":p5Variable,"WEBGL2":p5Variable,"ARROW":p5Variable,"CROSS":p5Variable,"HAND":p5Variable,"MOVE":p5Variable,"TEXT":p5Variable,"WAIT":p5Variable,"HALF_PI":p5Variable,"PI":p5Variable,"QUARTER_PI":p5Variable,"TAU":p5Variable,"TWO_PI":p5Variable,"DEGREES":p5Variable,"RADIANS":p5Variable,"CORNER":p5Variable,"CORNERS":p5Variable,"RADIUS":p5Variable,"RIGHT":p5Variable,"LEFT":p5Variable,"CENTER":p5Variable,"TOP":p5Variable,"BOTTOM":p5Variable,"BASELINE":p5Variable,"POINTS":p5Variable,"LINES":p5Variable,"LINE_STRIP":p5Variable,"LINE_LOOP":p5Variable,"TRIANGLES":p5Variable,"TRIANGLE_FAN":p5Variable,"TRIANGLE_STRIP":p5Variable,"QUADS":p5Variable,"QUAD_STRIP":p5Variable,"TESS":p5Variable,"CLOSE":p5Variable,"OPEN":p5Variable,"CHORD":p5Variable,"PIE":p5Variable,"PROJECT":p5Variable,"SQUARE":p5Variable,"ROUND":p5Variable,"BEVEL":p5Variable,"MITER":p5Variable,"RGB":p5Variable,"HSB":p5Variable,"HSL":p5Variable,"AUTO":p5Variable,"ALT":p5Variable,"BACKSPACE":p5Variable,"CONTROL":p5Variable,"DELETE":p5Variable,"DOWN_ARROW":p5Variable,"ENTER":p5Variable,"ESCAPE":p5Variable,"LEFT_ARROW":p5Variable,"OPTION":p5Variable,"RETURN":p5Variable,"RIGHT_ARROW":p5Variable,"SHIFT":p5Variable,"TAB":p5Variable,"UP_ARROW":p5Variable,"BLEND":p5Variable,"REMOVE":p5Variable,"ADD":p5Variable,"DARKEST":p5Variable,"LIGHTEST":p5Variable,"DIFFERENCE":p5Variable,"SUBTRACT":p5Variable,"EXCLUSION":p5Variable,"MULTIPLY":p5Variable,"SCREEN":p5Variable,"REPLACE":p5Variable,"OVERLAY":p5Variable,"HARD_LIGHT":p5Variable,"SOFT_LIGHT":p5Variable,"DODGE":p5Variable,"BURN":p5Variable,"THRESHOLD":p5Variable,"GRAY":p5Variable,"OPAQUE":p5Variable,"INVERT":p5Variable,"POSTERIZE":p5Variable,"DILATE":p5Variable,"ERODE":p5Variable,"BLUR":p5Variable,"NORMAL":p5Variable,"ITALIC":p5Variable,"BOLD":p5Variable,"BOLDITALIC":p5Variable,"CHAR":p5Variable,"WORD":p5Variable,"LINEAR":p5Variable,"QUADRATIC":p5Variable,"BEZIER":p5Variable,"CURVE":p5Variable,"STROKE":p5Variable,"FILL":p5Variable,"TEXTURE":p5Variable,"IMMEDIATE":p5Variable,"IMAGE":p5Variable,"NEAREST":p5Variable,"REPEAT":p5Variable,"CLAMP":p5Variable,"MIRROR":p5Variable,"FLAT":p5Variable,"SMOOTH":p5Variable,"LANDSCAPE":p5Variable,"PORTRAIT":p5Variable,"GRID":p5Variable,"AXES":p5Variable,"LABEL":p5Variable,"FALLBACK":p5Variable,"CONTAIN":p5Variable,"COVER":p5Variable,"UNSIGNED_BYTE":p5Variable,"UNSIGNED_INT":p5Variable,"FLOAT":p5Variable,"HALF_FLOAT":p5Variable,"RGBA":p5Variable,"frameCount":p5Variable,"deltaTime":p5Variable,"focused":p5Variable,"webglVersion":p5Variable,"displayWidth":p5Variable,"displayHeight":p5Variable,"windowWidth":p5Variable,"windowHeight":p5Variable,"width":p5Variable,"height":p5Variable,"disableFriendlyErrors":p5Variable,"drawingContext":p5Variable,"deviceOrientation":p5Variable,"accelerationX":p5Variable,"accelerationY":p5Variable,"accelerationZ":p5Variable,"pAccelerationX":p5Variable,"pAccelerationY":p5Variable,"pAccelerationZ":p5Variable,"rotationX":p5Variable,"rotationY":p5Variable,"rotationZ":p5Variable,"pRotationX":p5Variable,"pRotationY":p5Variable,"pRotationZ":p5Variable,"turnAxis":p5Variable,"keyIsPressed":p5Variable,"key":p5Variable,"keyCode":p5Variable,"movedX":p5Variable,"movedY":p5Variable,"mouseX":p5Variable,"mouseY":p5Variable,"pmouseX":p5Variable,"pmouseY":p5Variable,"winMouseX":p5Variable,"winMouseY":p5Variable,"pwinMouseX":p5Variable,"pwinMouseY":p5Variable,"mouseButton":p5Variable,"mouseIsPressed":p5Variable,"touches":p5Variable,"pixels":p5Variable,"soundOut":p5Variable}; -let p5FunctionKeywords = {"describe":p5Function,"describeElement":p5Function,"textOutput":p5Function,"gridOutput":p5Function,"alpha":p5Function,"blue":p5Function,"brightness":p5Function,"color":p5Function,"green":p5Function,"hue":p5Function,"lerpColor":p5Function,"lightness":p5Function,"red":p5Function,"saturation":p5Function,"beginClip":p5Function,"endClip":p5Function,"clip":p5Function,"background":p5Function,"clear":p5Function,"colorMode":p5Function,"fill":p5Function,"noFill":p5Function,"noStroke":p5Function,"stroke":p5Function,"erase":p5Function,"noErase":p5Function,"arc":p5Function,"ellipse":p5Function,"circle":p5Function,"line":p5Function,"point":p5Function,"quad":p5Function,"rect":p5Function,"square":p5Function,"triangle":p5Function,"ellipseMode":p5Function,"noSmooth":p5Function,"rectMode":p5Function,"smooth":p5Function,"strokeCap":p5Function,"strokeJoin":p5Function,"strokeWeight":p5Function,"bezier":p5Function,"bezierDetail":p5Function,"bezierPoint":p5Function,"bezierTangent":p5Function,"curve":p5Function,"curveDetail":p5Function,"curveTightness":p5Function,"curvePoint":p5Function,"curveTangent":p5Function,"beginContour":p5Function,"beginShape":p5Function,"bezierVertex":p5Function,"curveVertex":p5Function,"endContour":p5Function,"endShape":p5Function,"quadraticVertex":p5Function,"vertex":p5Function,"normal":p5Function,"print":p5Function,"cursor":p5Function,"frameRate":p5Function,"getTargetFrameRate":p5Function,"noCursor":p5Function,"windowResized":p5Function,"fullscreen":p5Function,"pixelDensity":p5Function,"displayDensity":p5Function,"getURL":p5Function,"getURLPath":p5Function,"getURLParams":p5Function,"preload":p5Function,"setup":p5Function,"draw":p5Function,"remove":p5Function,"createCanvas":p5Function,"resizeCanvas":p5Function,"noCanvas":p5Function,"createGraphics":p5Function,"createFramebuffer":p5Function,"clearDepth":p5Function,"blendMode":p5Function,"noLoop":p5Function,"loop":p5Function,"isLooping":p5Function,"push":p5Function,"pop":p5Function,"redraw":p5Function,"p5":p5Function,"applyMatrix":p5Function,"resetMatrix":p5Function,"rotate":p5Function,"rotateX":p5Function,"rotateY":p5Function,"rotateZ":p5Function,"scale":p5Function,"shearX":p5Function,"shearY":p5Function,"translate":p5Function,"storeItem":p5Function,"getItem":p5Function,"clearStorage":p5Function,"removeItem":p5Function,"createStringDict":p5Function,"createNumberDict":p5Function,"select":p5Function,"selectAll":p5Function,"removeElements":p5Function,"changed":p5Function,"input":p5Function,"createDiv":p5Function,"createP":p5Function,"createSpan":p5Function,"createImg":p5Function,"createA":p5Function,"createSlider":p5Function,"createButton":p5Function,"createCheckbox":p5Function,"createSelect":p5Function,"createRadio":p5Function,"createColorPicker":p5Function,"createInput":p5Function,"createFileInput":p5Function,"createVideo":p5Function,"createAudio":p5Function,"createCapture":p5Function,"createElement":p5Function,"setMoveThreshold":p5Function,"setShakeThreshold":p5Function,"deviceMoved":p5Function,"deviceTurned":p5Function,"deviceShaken":p5Function,"keyPressed":p5Function,"keyReleased":p5Function,"keyTyped":p5Function,"keyIsDown":p5Function,"mouseMoved":p5Function,"mouseDragged":p5Function,"mousePressed":p5Function,"mouseReleased":p5Function,"mouseClicked":p5Function,"doubleClicked":p5Function,"mouseWheel":p5Function,"requestPointerLock":p5Function,"exitPointerLock":p5Function,"touchStarted":p5Function,"touchMoved":p5Function,"touchEnded":p5Function,"createImage":p5Function,"saveCanvas":p5Function,"saveFrames":p5Function,"loadImage":p5Function,"saveGif":p5Function,"image":p5Function,"tint":p5Function,"noTint":p5Function,"imageMode":p5Function,"blend":p5Function,"copy":p5Function,"filter":p5Function,"get":p5Function,"loadPixels":p5Function,"set":p5Function,"updatePixels":p5Function,"loadJSON":p5Function,"loadStrings":p5Function,"loadTable":p5Function,"loadXML":p5Function,"loadBytes":p5Function,"httpGet":p5Function,"httpPost":p5Function,"httpDo":p5Function,"createWriter":p5Function,"save":p5Function,"saveJSON":p5Function,"saveStrings":p5Function,"saveTable":p5Function,"abs":p5Function,"ceil":p5Function,"constrain":p5Function,"dist":p5Function,"exp":p5Function,"floor":p5Function,"lerp":p5Function,"log":p5Function,"mag":p5Function,"map":p5Function,"max":p5Function,"min":p5Function,"norm":p5Function,"pow":p5Function,"round":p5Function,"sq":p5Function,"sqrt":p5Function,"fract":p5Function,"createVector":p5Function,"noise":p5Function,"noiseDetail":p5Function,"noiseSeed":p5Function,"randomSeed":p5Function,"random":p5Function,"randomGaussian":p5Function,"acos":p5Function,"asin":p5Function,"atan":p5Function,"atan2":p5Function,"cos":p5Function,"sin":p5Function,"tan":p5Function,"degrees":p5Function,"radians":p5Function,"angleMode":p5Function,"textAlign":p5Function,"textLeading":p5Function,"textSize":p5Function,"textStyle":p5Function,"textWidth":p5Function,"textAscent":p5Function,"textDescent":p5Function,"textWrap":p5Function,"loadFont":p5Function,"text":p5Function,"textFont":p5Function,"append":p5Function,"arrayCopy":p5Function,"concat":p5Function,"reverse":p5Function,"shorten":p5Function,"shuffle":p5Function,"sort":p5Function,"splice":p5Function,"subset":p5Function,"float":p5Function,"int":p5Function,"str":p5Function,"boolean":p5Function,"byte":p5Function,"char":p5Function,"unchar":p5Function,"hex":p5Function,"unhex":p5Function,"join":p5Function,"match":p5Function,"matchAll":p5Function,"nf":p5Function,"nfc":p5Function,"nfp":p5Function,"nfs":p5Function,"split":p5Function,"splitTokens":p5Function,"trim":p5Function,"day":p5Function,"hour":p5Function,"minute":p5Function,"millis":p5Function,"month":p5Function,"second":p5Function,"year":p5Function,"beginGeometry":p5Function,"endGeometry":p5Function,"buildGeometry":p5Function,"freeGeometry":p5Function,"plane":p5Function,"box":p5Function,"sphere":p5Function,"cylinder":p5Function,"cone":p5Function,"ellipsoid":p5Function,"torus":p5Function,"orbitControl":p5Function,"debugMode":p5Function,"noDebugMode":p5Function,"ambientLight":p5Function,"specularColor":p5Function,"directionalLight":p5Function,"pointLight":p5Function,"imageLight":p5Function,"panorama":p5Function,"lights":p5Function,"lightFalloff":p5Function,"spotLight":p5Function,"noLights":p5Function,"loadModel":p5Function,"model":p5Function,"loadShader":p5Function,"createShader":p5Function,"createFilterShader":p5Function,"shader":p5Function,"resetShader":p5Function,"texture":p5Function,"textureMode":p5Function,"textureWrap":p5Function,"normalMaterial":p5Function,"ambientMaterial":p5Function,"emissiveMaterial":p5Function,"specularMaterial":p5Function,"shininess":p5Function,"metalness":p5Function,"camera":p5Function,"perspective":p5Function,"linePerspective":p5Function,"ortho":p5Function,"frustum":p5Function,"createCamera":p5Function,"setCamera":p5Function,"setAttributes":p5Function,"getAudioContext":p5Function,"userStartAudio":p5Function,"getOutputVolume":p5Function,"outputVolume":p5Function,"sampleRate":p5Function,"freqToMidi":p5Function,"midiToFreq":p5Function,"soundFormats":p5Function,"saveSound":p5Function,"loadSound":p5Function,"createConvolver":p5Function,"setBPM":p5Function}; +/* eslint-disable */ +/* generated: do not edit! helper file for syntax highlighting. generated by update-syntax-highlighting script */ +var p5Function = { type: 'variable', style: 'p5-function' }; +var p5Variable = { type: 'variable', style: 'p5-variable' }; +let p5VariableKeywords = { + VERSION: p5Variable, + P2D: p5Variable, + WEBGL: p5Variable, + WEBGL2: p5Variable, + ARROW: p5Variable, + CROSS: p5Variable, + HAND: p5Variable, + MOVE: p5Variable, + TEXT: p5Variable, + WAIT: p5Variable, + HALF_PI: p5Variable, + PI: p5Variable, + QUARTER_PI: p5Variable, + TAU: p5Variable, + TWO_PI: p5Variable, + DEGREES: p5Variable, + RADIANS: p5Variable, + CORNER: p5Variable, + CORNERS: p5Variable, + RADIUS: p5Variable, + RIGHT: p5Variable, + LEFT: p5Variable, + CENTER: p5Variable, + TOP: p5Variable, + BOTTOM: p5Variable, + BASELINE: p5Variable, + POINTS: p5Variable, + LINES: p5Variable, + LINE_STRIP: p5Variable, + LINE_LOOP: p5Variable, + TRIANGLES: p5Variable, + TRIANGLE_FAN: p5Variable, + TRIANGLE_STRIP: p5Variable, + QUADS: p5Variable, + QUAD_STRIP: p5Variable, + TESS: p5Variable, + CLOSE: p5Variable, + OPEN: p5Variable, + CHORD: p5Variable, + PIE: p5Variable, + PROJECT: p5Variable, + SQUARE: p5Variable, + ROUND: p5Variable, + BEVEL: p5Variable, + MITER: p5Variable, + RGB: p5Variable, + HSB: p5Variable, + HSL: p5Variable, + AUTO: p5Variable, + ALT: p5Variable, + BACKSPACE: p5Variable, + CONTROL: p5Variable, + DELETE: p5Variable, + DOWN_ARROW: p5Variable, + ENTER: p5Variable, + ESCAPE: p5Variable, + LEFT_ARROW: p5Variable, + OPTION: p5Variable, + RETURN: p5Variable, + RIGHT_ARROW: p5Variable, + SHIFT: p5Variable, + TAB: p5Variable, + UP_ARROW: p5Variable, + BLEND: p5Variable, + REMOVE: p5Variable, + ADD: p5Variable, + DARKEST: p5Variable, + LIGHTEST: p5Variable, + DIFFERENCE: p5Variable, + SUBTRACT: p5Variable, + EXCLUSION: p5Variable, + MULTIPLY: p5Variable, + SCREEN: p5Variable, + REPLACE: p5Variable, + OVERLAY: p5Variable, + HARD_LIGHT: p5Variable, + SOFT_LIGHT: p5Variable, + DODGE: p5Variable, + BURN: p5Variable, + THRESHOLD: p5Variable, + GRAY: p5Variable, + OPAQUE: p5Variable, + INVERT: p5Variable, + POSTERIZE: p5Variable, + DILATE: p5Variable, + ERODE: p5Variable, + BLUR: p5Variable, + NORMAL: p5Variable, + ITALIC: p5Variable, + BOLD: p5Variable, + BOLDITALIC: p5Variable, + CHAR: p5Variable, + WORD: p5Variable, + LINEAR: p5Variable, + QUADRATIC: p5Variable, + BEZIER: p5Variable, + CURVE: p5Variable, + STROKE: p5Variable, + FILL: p5Variable, + TEXTURE: p5Variable, + IMMEDIATE: p5Variable, + IMAGE: p5Variable, + NEAREST: p5Variable, + REPEAT: p5Variable, + CLAMP: p5Variable, + MIRROR: p5Variable, + FLAT: p5Variable, + SMOOTH: p5Variable, + LANDSCAPE: p5Variable, + PORTRAIT: p5Variable, + GRID: p5Variable, + AXES: p5Variable, + LABEL: p5Variable, + FALLBACK: p5Variable, + CONTAIN: p5Variable, + COVER: p5Variable, + UNSIGNED_BYTE: p5Variable, + UNSIGNED_INT: p5Variable, + FLOAT: p5Variable, + HALF_FLOAT: p5Variable, + RGBA: p5Variable, + frameCount: p5Variable, + deltaTime: p5Variable, + focused: p5Variable, + webglVersion: p5Variable, + displayWidth: p5Variable, + displayHeight: p5Variable, + windowWidth: p5Variable, + windowHeight: p5Variable, + width: p5Variable, + height: p5Variable, + disableFriendlyErrors: p5Variable, + drawingContext: p5Variable, + deviceOrientation: p5Variable, + accelerationX: p5Variable, + accelerationY: p5Variable, + accelerationZ: p5Variable, + pAccelerationX: p5Variable, + pAccelerationY: p5Variable, + pAccelerationZ: p5Variable, + rotationX: p5Variable, + rotationY: p5Variable, + rotationZ: p5Variable, + pRotationX: p5Variable, + pRotationY: p5Variable, + pRotationZ: p5Variable, + turnAxis: p5Variable, + keyIsPressed: p5Variable, + key: p5Variable, + keyCode: p5Variable, + movedX: p5Variable, + movedY: p5Variable, + mouseX: p5Variable, + mouseY: p5Variable, + pmouseX: p5Variable, + pmouseY: p5Variable, + winMouseX: p5Variable, + winMouseY: p5Variable, + pwinMouseX: p5Variable, + pwinMouseY: p5Variable, + mouseButton: p5Variable, + mouseIsPressed: p5Variable, + touches: p5Variable, + pixels: p5Variable, + soundOut: p5Variable +}; +let p5FunctionKeywords = { + describe: p5Function, + describeElement: p5Function, + textOutput: p5Function, + gridOutput: p5Function, + alpha: p5Function, + blue: p5Function, + brightness: p5Function, + color: p5Function, + green: p5Function, + hue: p5Function, + lerpColor: p5Function, + lightness: p5Function, + red: p5Function, + saturation: p5Function, + beginClip: p5Function, + endClip: p5Function, + clip: p5Function, + background: p5Function, + clear: p5Function, + colorMode: p5Function, + fill: p5Function, + noFill: p5Function, + noStroke: p5Function, + stroke: p5Function, + erase: p5Function, + noErase: p5Function, + arc: p5Function, + ellipse: p5Function, + circle: p5Function, + line: p5Function, + point: p5Function, + quad: p5Function, + rect: p5Function, + square: p5Function, + triangle: p5Function, + ellipseMode: p5Function, + noSmooth: p5Function, + rectMode: p5Function, + smooth: p5Function, + strokeCap: p5Function, + strokeJoin: p5Function, + strokeWeight: p5Function, + bezier: p5Function, + bezierDetail: p5Function, + bezierPoint: p5Function, + bezierTangent: p5Function, + curve: p5Function, + curveDetail: p5Function, + curveTightness: p5Function, + curvePoint: p5Function, + curveTangent: p5Function, + beginContour: p5Function, + beginShape: p5Function, + bezierVertex: p5Function, + curveVertex: p5Function, + endContour: p5Function, + endShape: p5Function, + quadraticVertex: p5Function, + vertex: p5Function, + normal: p5Function, + print: p5Function, + cursor: p5Function, + frameRate: p5Function, + getTargetFrameRate: p5Function, + noCursor: p5Function, + windowResized: p5Function, + fullscreen: p5Function, + pixelDensity: p5Function, + displayDensity: p5Function, + getURL: p5Function, + getURLPath: p5Function, + getURLParams: p5Function, + preload: p5Function, + setup: p5Function, + draw: p5Function, + remove: p5Function, + createCanvas: p5Function, + resizeCanvas: p5Function, + noCanvas: p5Function, + createGraphics: p5Function, + createFramebuffer: p5Function, + clearDepth: p5Function, + blendMode: p5Function, + noLoop: p5Function, + loop: p5Function, + isLooping: p5Function, + push: p5Function, + pop: p5Function, + redraw: p5Function, + p5: p5Function, + applyMatrix: p5Function, + resetMatrix: p5Function, + rotate: p5Function, + rotateX: p5Function, + rotateY: p5Function, + rotateZ: p5Function, + scale: p5Function, + shearX: p5Function, + shearY: p5Function, + translate: p5Function, + storeItem: p5Function, + getItem: p5Function, + clearStorage: p5Function, + removeItem: p5Function, + createStringDict: p5Function, + createNumberDict: p5Function, + select: p5Function, + selectAll: p5Function, + removeElements: p5Function, + changed: p5Function, + input: p5Function, + createDiv: p5Function, + createP: p5Function, + createSpan: p5Function, + createImg: p5Function, + createA: p5Function, + createSlider: p5Function, + createButton: p5Function, + createCheckbox: p5Function, + createSelect: p5Function, + createRadio: p5Function, + createColorPicker: p5Function, + createInput: p5Function, + createFileInput: p5Function, + createVideo: p5Function, + createAudio: p5Function, + createCapture: p5Function, + createElement: p5Function, + setMoveThreshold: p5Function, + setShakeThreshold: p5Function, + deviceMoved: p5Function, + deviceTurned: p5Function, + deviceShaken: p5Function, + keyPressed: p5Function, + keyReleased: p5Function, + keyTyped: p5Function, + keyIsDown: p5Function, + mouseMoved: p5Function, + mouseDragged: p5Function, + mousePressed: p5Function, + mouseReleased: p5Function, + mouseClicked: p5Function, + doubleClicked: p5Function, + mouseWheel: p5Function, + requestPointerLock: p5Function, + exitPointerLock: p5Function, + touchStarted: p5Function, + touchMoved: p5Function, + touchEnded: p5Function, + createImage: p5Function, + saveCanvas: p5Function, + saveFrames: p5Function, + loadImage: p5Function, + saveGif: p5Function, + image: p5Function, + tint: p5Function, + noTint: p5Function, + imageMode: p5Function, + blend: p5Function, + copy: p5Function, + filter: p5Function, + get: p5Function, + loadPixels: p5Function, + set: p5Function, + updatePixels: p5Function, + loadJSON: p5Function, + loadStrings: p5Function, + loadTable: p5Function, + loadXML: p5Function, + loadBytes: p5Function, + httpGet: p5Function, + httpPost: p5Function, + httpDo: p5Function, + createWriter: p5Function, + save: p5Function, + saveJSON: p5Function, + saveStrings: p5Function, + saveTable: p5Function, + abs: p5Function, + ceil: p5Function, + constrain: p5Function, + dist: p5Function, + exp: p5Function, + floor: p5Function, + lerp: p5Function, + log: p5Function, + mag: p5Function, + map: p5Function, + max: p5Function, + min: p5Function, + norm: p5Function, + pow: p5Function, + round: p5Function, + sq: p5Function, + sqrt: p5Function, + fract: p5Function, + createVector: p5Function, + noise: p5Function, + noiseDetail: p5Function, + noiseSeed: p5Function, + randomSeed: p5Function, + random: p5Function, + randomGaussian: p5Function, + acos: p5Function, + asin: p5Function, + atan: p5Function, + atan2: p5Function, + cos: p5Function, + sin: p5Function, + tan: p5Function, + degrees: p5Function, + radians: p5Function, + angleMode: p5Function, + textAlign: p5Function, + textLeading: p5Function, + textSize: p5Function, + textStyle: p5Function, + textWidth: p5Function, + textAscent: p5Function, + textDescent: p5Function, + textWrap: p5Function, + loadFont: p5Function, + text: p5Function, + textFont: p5Function, + append: p5Function, + arrayCopy: p5Function, + concat: p5Function, + reverse: p5Function, + shorten: p5Function, + shuffle: p5Function, + sort: p5Function, + splice: p5Function, + subset: p5Function, + float: p5Function, + int: p5Function, + str: p5Function, + boolean: p5Function, + byte: p5Function, + char: p5Function, + unchar: p5Function, + hex: p5Function, + unhex: p5Function, + join: p5Function, + match: p5Function, + matchAll: p5Function, + nf: p5Function, + nfc: p5Function, + nfp: p5Function, + nfs: p5Function, + split: p5Function, + splitTokens: p5Function, + trim: p5Function, + day: p5Function, + hour: p5Function, + minute: p5Function, + millis: p5Function, + month: p5Function, + second: p5Function, + year: p5Function, + beginGeometry: p5Function, + endGeometry: p5Function, + buildGeometry: p5Function, + freeGeometry: p5Function, + plane: p5Function, + box: p5Function, + sphere: p5Function, + cylinder: p5Function, + cone: p5Function, + ellipsoid: p5Function, + torus: p5Function, + orbitControl: p5Function, + debugMode: p5Function, + noDebugMode: p5Function, + ambientLight: p5Function, + specularColor: p5Function, + directionalLight: p5Function, + pointLight: p5Function, + imageLight: p5Function, + panorama: p5Function, + lights: p5Function, + lightFalloff: p5Function, + spotLight: p5Function, + noLights: p5Function, + loadModel: p5Function, + model: p5Function, + loadShader: p5Function, + createShader: p5Function, + createFilterShader: p5Function, + shader: p5Function, + resetShader: p5Function, + texture: p5Function, + textureMode: p5Function, + textureWrap: p5Function, + normalMaterial: p5Function, + ambientMaterial: p5Function, + emissiveMaterial: p5Function, + specularMaterial: p5Function, + shininess: p5Function, + metalness: p5Function, + camera: p5Function, + perspective: p5Function, + linePerspective: p5Function, + ortho: p5Function, + frustum: p5Function, + createCamera: p5Function, + setCamera: p5Function, + setAttributes: p5Function, + getAudioContext: p5Function, + userStartAudio: p5Function, + getOutputVolume: p5Function, + outputVolume: p5Function, + sampleRate: p5Function, + freqToMidi: p5Function, + midiToFreq: p5Function, + soundFormats: p5Function, + saveSound: p5Function, + loadSound: p5Function, + createConvolver: p5Function, + setBPM: p5Function +}; exports.p5FunctionKeywords = p5FunctionKeywords; exports.p5VariableKeywords = p5VariableKeywords; diff --git a/client/utils/p5-reference-functions.json b/client/utils/p5-reference-functions.json index 478b264434..6d9a697c2a 100644 --- a/client/utils/p5-reference-functions.json +++ b/client/utils/p5-reference-functions.json @@ -1,379 +1,381 @@ { "functions": { "list": [ - "abs", - "accelerationX", - "accelerationY", - "accelerationZ", - "acos", - "alpha", - "ambientLight", - "ambientMaterial", - "angleMode", - "append", - "applyMatrix", - "arc", - "arrayCopy", - "asin", - "atan", - "atan2", - "background", - "baseColorShader", - "baseMaterialShader", - "baseNormalShader", - "baseStrokeShader", - "beginClip", - "beginContour", - "beginGeometry", - "beginShape", - "bezier", - "bezierDetail", - "bezierPoint", - "bezierTangent", - "bezierVertex", - "blend", - "blendMode", - "blue", - "boolean", - "box", - "brightness", - "buildGeometry", - "byte", - "camera", - "ceil", - "changed", - "char", - "circle", - "class", - "clear", - "clearDepth", - "clearStorage", - "clip", - "color", - "colorMode", - "concat", - "cone", - "console", - "constrain", - "copy", - "cos", - "createA", - "createAudio", - "createButton", - "createCamera", - "createCanvas", - "createCapture", - "createCheckbox", - "createColorPicker", - "createConvolver", - "createDiv", - "createElement", - "createFileInput", - "createFilterShader", - "createFramebuffer", - "createGraphics", - "createImage", - "createImg", - "createInput", - "createModel", - "createNumberDict", - "createP", - "createRadio", - "createSelect", - "createShader", - "createSlider", - "createSpan", - "createStringDict", - "createVector", - "createVideo", - "createWriter", - "cursor", - "curve", - "curveDetail", - "curvePoint", - "curveTangent", - "curveTightness", - "curveVertex", - "cylinder", - "day", - "debugMode", - "degrees", - "deltaTime", - "describe", - "describeElement", - "deviceMoved", - "deviceOrientation", - "deviceShaken", - "deviceTurned", - "directionalLight", - "disableFriendlyErrors", - "displayDensity", - "displayHeight", - "displayWidth", - "dist", - "doubleClicked", - "draw", - "drawingContext", - "ellipse", - "ellipseMode", - "ellipsoid", - "emissiveMaterial", - "endClip", - "endContour", - "endGeometry", - "endShape", - "erase", - "exitPointerLock", - "exp", - "fill", - "filter", - "float", - "floor", - "focused", - "for", - "fract", - "frameCount", - "frameRate", - "freeGeometry", - "freqToMidi", - "frustum", - "fullscreen", - "function", - "get", - "getAudioContext", - "getItem", - "getOutputVolume", - "getTargetFrameRate", - "getURL", - "getURLParams", - "getURLPath", - "green", - "gridOutput", - "height", - "hex", - "hour", - "httpDo", - "httpGet", - "httpPost", - "hue", - "if", - "image", - "imageLight", - "imageMode", - "input", - "int", - "isLooping", - "join", - "key", - "keyCode", - "keyIsDown", - "keyIsPressed", - "keyPressed", - "keyReleased", - "keyTyped", - "lerp", - "lerpColor", - "let", - "lightFalloff", - "lightness", - "lights", - "line", - "linePerspective", - "loadBytes", - "loadFont", - "loadImage", - "loadJSON", - "loadModel", - "loadPixels", - "loadShader", - "loadSound", - "loadStrings", - "loadTable", - "loadXML", - "log", - "loop", - "mag", - "map", - "match", - "matchAll", - "max", - "metalness", - "midiToFreq", - "millis", - "min", - "minute", - "model", - "month", - "mouseButton", - "mouseClicked", - "mouseDragged", - "mouseIsPressed", - "mouseMoved", - "mousePressed", - "mouseReleased", - "mouseWheel", - "mouseX", - "mouseY", - "movedX", - "movedY", - "nf", - "nfc", - "nfp", - "nfs", - "noCanvas", - "noCursor", - "noDebugMode", - "noErase", - "noFill", - "noise", - "noiseDetail", - "noiseSeed", - "noLights", - "noLoop", - "norm", - "normal", - "normalMaterial", - "noSmooth", - "noStroke", - "noTint", - "orbitControl", - "ortho", - "outputVolume", - "pAccelerationX", - "pAccelerationY", - "pAccelerationZ", - "paletteLerp", - "panorama", - "perspective", - "pixelDensity", - "pixels", - "plane", - "pmouseX", - "pmouseY", - "point", - "pointLight", - "pop", - "pow", - "preload", - "print", - "pRotationX", - "pRotationY", - "pRotationZ", - "push", - "pwinMouseX", - "pwinMouseY", - "quad", - "quadraticVertex", - "radians", - "random", - "randomGaussian", - "randomSeed", - "rect", - "rectMode", - "red", - "redraw", - "remove", - "removeElements", - "removeItem", - "requestPointerLock", - "resetMatrix", - "resetShader", - "resizeCanvas", - "reverse", - "rotate", - "rotateX", - "rotateY", - "rotateZ", - "rotationX", - "rotationY", - "rotationZ", - "round", - "sampleRate", - "saturation", - "save", - "saveCanvas", - "saveFrames", - "saveGif", - "saveJSON", - "saveSound", - "saveStrings", - "saveTable", - "scale", - "second", - "select", - "selectAll", - "set", - "setAttributes", - "setBPM", - "setCamera", - "setMoveThreshold", - "setShakeThreshold", - "setup", - "shader", - "shearX", - "shearY", - "shininess", - "shorten", - "shuffle", - "sin", - "smooth", - "sort", - "soundFormats", - "soundOut", - "specularColor", - "specularMaterial", - "sphere", - "splice", - "split", - "splitTokens", - "spotLight", - "sq", - "sqrt", - "square", - "storeItem", - "str", - "stroke", - "strokeCap", - "strokeJoin", - "strokeWeight", - "subset", - "tan", - "text", - "textAlign", - "textAscent", - "textDescent", - "textFont", - "textLeading", - "textOutput", - "textSize", - "textStyle", - "texture", - "textureMode", - "textureWrap", - "textWidth", - "textWrap", - "tint", - "torus", - "touchEnded", - "touches", - "touchMoved", - "touchStarted", - "translate", - "triangle", - "trim", - "turnAxis", - "unchar", - "unhex", - "updatePixels", - "userStartAudio", - "vertex", - "webglVersion", - "while", - "width", - "windowHeight", - "windowResized", - "windowWidth", - "winMouseX", - "winMouseY", - "year" -]}} \ No newline at end of file + "abs", + "accelerationX", + "accelerationY", + "accelerationZ", + "acos", + "alpha", + "ambientLight", + "ambientMaterial", + "angleMode", + "append", + "applyMatrix", + "arc", + "arrayCopy", + "asin", + "atan", + "atan2", + "background", + "baseColorShader", + "baseMaterialShader", + "baseNormalShader", + "baseStrokeShader", + "beginClip", + "beginContour", + "beginGeometry", + "beginShape", + "bezier", + "bezierDetail", + "bezierPoint", + "bezierTangent", + "bezierVertex", + "blend", + "blendMode", + "blue", + "boolean", + "box", + "brightness", + "buildGeometry", + "byte", + "camera", + "ceil", + "changed", + "char", + "circle", + "class", + "clear", + "clearDepth", + "clearStorage", + "clip", + "color", + "colorMode", + "concat", + "cone", + "console", + "constrain", + "copy", + "cos", + "createA", + "createAudio", + "createButton", + "createCamera", + "createCanvas", + "createCapture", + "createCheckbox", + "createColorPicker", + "createConvolver", + "createDiv", + "createElement", + "createFileInput", + "createFilterShader", + "createFramebuffer", + "createGraphics", + "createImage", + "createImg", + "createInput", + "createModel", + "createNumberDict", + "createP", + "createRadio", + "createSelect", + "createShader", + "createSlider", + "createSpan", + "createStringDict", + "createVector", + "createVideo", + "createWriter", + "cursor", + "curve", + "curveDetail", + "curvePoint", + "curveTangent", + "curveTightness", + "curveVertex", + "cylinder", + "day", + "debugMode", + "degrees", + "deltaTime", + "describe", + "describeElement", + "deviceMoved", + "deviceOrientation", + "deviceShaken", + "deviceTurned", + "directionalLight", + "disableFriendlyErrors", + "displayDensity", + "displayHeight", + "displayWidth", + "dist", + "doubleClicked", + "draw", + "drawingContext", + "ellipse", + "ellipseMode", + "ellipsoid", + "emissiveMaterial", + "endClip", + "endContour", + "endGeometry", + "endShape", + "erase", + "exitPointerLock", + "exp", + "fill", + "filter", + "float", + "floor", + "focused", + "for", + "fract", + "frameCount", + "frameRate", + "freeGeometry", + "freqToMidi", + "frustum", + "fullscreen", + "function", + "get", + "getAudioContext", + "getItem", + "getOutputVolume", + "getTargetFrameRate", + "getURL", + "getURLParams", + "getURLPath", + "green", + "gridOutput", + "height", + "hex", + "hour", + "httpDo", + "httpGet", + "httpPost", + "hue", + "if", + "image", + "imageLight", + "imageMode", + "input", + "int", + "isLooping", + "join", + "key", + "keyCode", + "keyIsDown", + "keyIsPressed", + "keyPressed", + "keyReleased", + "keyTyped", + "lerp", + "lerpColor", + "let", + "lightFalloff", + "lightness", + "lights", + "line", + "linePerspective", + "loadBytes", + "loadFont", + "loadImage", + "loadJSON", + "loadModel", + "loadPixels", + "loadShader", + "loadSound", + "loadStrings", + "loadTable", + "loadXML", + "log", + "loop", + "mag", + "map", + "match", + "matchAll", + "max", + "metalness", + "midiToFreq", + "millis", + "min", + "minute", + "model", + "month", + "mouseButton", + "mouseClicked", + "mouseDragged", + "mouseIsPressed", + "mouseMoved", + "mousePressed", + "mouseReleased", + "mouseWheel", + "mouseX", + "mouseY", + "movedX", + "movedY", + "nf", + "nfc", + "nfp", + "nfs", + "noCanvas", + "noCursor", + "noDebugMode", + "noErase", + "noFill", + "noise", + "noiseDetail", + "noiseSeed", + "noLights", + "noLoop", + "norm", + "normal", + "normalMaterial", + "noSmooth", + "noStroke", + "noTint", + "orbitControl", + "ortho", + "outputVolume", + "pAccelerationX", + "pAccelerationY", + "pAccelerationZ", + "paletteLerp", + "panorama", + "perspective", + "pixelDensity", + "pixels", + "plane", + "pmouseX", + "pmouseY", + "point", + "pointLight", + "pop", + "pow", + "preload", + "print", + "pRotationX", + "pRotationY", + "pRotationZ", + "push", + "pwinMouseX", + "pwinMouseY", + "quad", + "quadraticVertex", + "radians", + "random", + "randomGaussian", + "randomSeed", + "rect", + "rectMode", + "red", + "redraw", + "remove", + "removeElements", + "removeItem", + "requestPointerLock", + "resetMatrix", + "resetShader", + "resizeCanvas", + "reverse", + "rotate", + "rotateX", + "rotateY", + "rotateZ", + "rotationX", + "rotationY", + "rotationZ", + "round", + "sampleRate", + "saturation", + "save", + "saveCanvas", + "saveFrames", + "saveGif", + "saveJSON", + "saveSound", + "saveStrings", + "saveTable", + "scale", + "second", + "select", + "selectAll", + "set", + "setAttributes", + "setBPM", + "setCamera", + "setMoveThreshold", + "setShakeThreshold", + "setup", + "shader", + "shearX", + "shearY", + "shininess", + "shorten", + "shuffle", + "sin", + "smooth", + "sort", + "soundFormats", + "soundOut", + "specularColor", + "specularMaterial", + "sphere", + "splice", + "split", + "splitTokens", + "spotLight", + "sq", + "sqrt", + "square", + "storeItem", + "str", + "stroke", + "strokeCap", + "strokeJoin", + "strokeWeight", + "subset", + "tan", + "text", + "textAlign", + "textAscent", + "textDescent", + "textFont", + "textLeading", + "textOutput", + "textSize", + "textStyle", + "texture", + "textureMode", + "textureWrap", + "textWidth", + "textWrap", + "tint", + "torus", + "touchEnded", + "touches", + "touchMoved", + "touchStarted", + "translate", + "triangle", + "trim", + "turnAxis", + "unchar", + "unhex", + "updatePixels", + "userStartAudio", + "vertex", + "webglVersion", + "while", + "width", + "windowHeight", + "windowResized", + "windowWidth", + "winMouseX", + "winMouseY", + "year" + ] + } +} diff --git a/client/utils/p5-scope-function-access-map.json b/client/utils/p5-scope-function-access-map.json index f2a7a18502..cea36ccbed 100644 --- a/client/utils/p5-scope-function-access-map.json +++ b/client/utils/p5-scope-function-access-map.json @@ -215,11 +215,7 @@ "vertex", "year" ], - "blacklist":[ - "draw", - "setup", - "preload" - ] + "blacklist": ["draw", "setup", "preload"] }, "draw": { "whitelist": [ @@ -342,8 +338,20 @@ "triangle", "vertex" ], - "blacklist":[ - "createCanvas", "let","const", "var", "loadJSON", "loadStrings","loadShader","loadTable","loadXML","save","draw", "setup", "preload" + "blacklist": [ + "createCanvas", + "let", + "const", + "var", + "loadJSON", + "loadStrings", + "loadShader", + "loadTable", + "loadXML", + "save", + "draw", + "setup", + "preload" ] }, "global": { @@ -404,11 +412,7 @@ "loadXML", "soundFormats" ], - "blacklist":[ - "preload", - "setup", - "draw" - ] + "blacklist": ["preload", "setup", "draw"] }, "doubleClicked": { "whitelist": [ @@ -436,44 +440,24 @@ ] }, "mouseReleased": { - "whitelist": [ - "fill", - "noStroke", - "setAttributes", - "stroke" - ] + "whitelist": ["fill", "noStroke", "setAttributes", "stroke"] }, "mouseClicked": { - "whitelist": [ - "fill", - "strokeWeight" - ] + "whitelist": ["fill", "strokeWeight"] }, "windowResized": { - "whitelist": [ - "resizeCanvas" - ] + "whitelist": ["resizeCanvas"] }, "keyPressed": { - "whitelist": [ - "saveFrames", - "saveGif" - ] + "whitelist": ["saveFrames", "saveGif"] }, "deviceMoved": { - "whitelist": [ - "setMoveThreshold", - "setShakeThreshold" - ] + "whitelist": ["setMoveThreshold", "setShakeThreshold"] }, "touchStarted": { - "whitelist": [ - "random" - ] + "whitelist": ["random"] }, "touchEnded": { - "whitelist": [ - "random" - ] + "whitelist": ["random"] } -} \ No newline at end of file +} diff --git a/client/utils/reduxFormUtils.ts b/client/utils/reduxFormUtils.ts index 8ef0a0259e..7b512d6dd0 100644 --- a/client/utils/reduxFormUtils.ts +++ b/client/utils/reduxFormUtils.ts @@ -1,7 +1,7 @@ import i18n from 'i18next'; -// eslint-disable-next-line max-len -const EMAIL_REGEX = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/i; +const EMAIL_REGEX = + /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/i; const USERNAME_REGEX = /^[a-zA-Z0-9._-]{1,20}$/; type Email = { email: string }; @@ -14,14 +14,10 @@ type NewPassword = { newPassword: string }; type UsernameAndEmail = Username & Email; type PasswordsConfirm = Password & ConfirmPassword; -/** Validation errors for site forms */ export type FormErrors = Partial< Email & Username & Password & ConfirmPassword & CurrentPassword & NewPassword >; -// === Internal helper functions: ===== - -/** Processes form & mutates errors to add any `username` & `email` errors */ function validateUsernameEmail( formProps: Partial, errors: FormErrors @@ -41,7 +37,6 @@ function validateUsernameEmail( } } -/** Processes form & mutates errors to add any `password` and `confirmPassword` errors */ function validatePasswords( formProps: Partial, errors: FormErrors @@ -64,12 +59,8 @@ function validatePasswords( } } -// ====== PUBLIC: ======== - -// Account Form: export type AccountForm = UsernameAndEmail & CurrentPassword & NewPassword; -/** Validation for the Account Form */ export function validateSettings( formProps: Partial ): Partial { @@ -92,10 +83,8 @@ export function validateSettings( return errors; } -// Login form: export type LoginForm = UsernameAndEmail & Password; -/** Validation for the Login Form */ export function validateLogin( formProps: Partial ): Partial { @@ -111,7 +100,6 @@ export function validateLogin( export type NewPasswordForm = PasswordsConfirm; -/** Validation for the New Password Form */ export function validateNewPassword( formProps: Partial ): Partial { @@ -120,10 +108,8 @@ export function validateNewPassword( return errors; } -// Signup Form: export type SignupForm = UsernameAndEmail & PasswordsConfirm; -/** Validation for the Signup Form */ export function validateSignup( formProps: Partial ): Partial { @@ -135,10 +121,8 @@ export function validateSignup( return errors; } -// Reset Password Form: export type ResetPasswordForm = Email; -/** Validation for the Reset Password Form */ export function validateResetPassword( formProps: Partial ): Partial { diff --git a/contributor_docs/GSOC_hinter_and_refactoring_changes.md b/contributor_docs/GSOC_hinter_and_refactoring_changes.md index 688127880e..1438be68ba 100644 --- a/contributor_docs/GSOC_hinter_and_refactoring_changes.md +++ b/contributor_docs/GSOC_hinter_and_refactoring_changes.md @@ -1,12 +1,15 @@ # GSoC 2025: p5.js Autocomplete Hinter & Refactoring System + This readme elaborates on the core components of the context-aware autocomplete hinter, refactoring utilities, and supporting data structures developed as part of Google Summer of Code 2025. The goal is to enable smart context-aware autocompletion, jump-to-definition, and safe variable renaming. # Project Overview ## Autocomplete Hinter Context-Aware Functionality + The following files and modules work together to make the p5.js autocomplete hinter context-aware: ### p5CodeAstAnalyzer.js + Purpose: Parses user-written p5.js code using Babel and extracts structural information: - Maps variable names to p5 class instances @@ -22,6 +25,7 @@ Key Output Maps: - userDefinedClassMetadata: Metadata for user-defined classes (methods, constructor properties) ### context-aware-hinter.js + Purpose: Provides code autocompletion hints based on: - Current cursor context (draw, setup, etc.) @@ -37,12 +41,15 @@ Features: - Ranks hints by type and scope relevance ### getContext.js + Purpose: Get the context of the cursor, i.e. inside what function is the cursor in ## Context-Aware Renaming Functionality + The following files ensure context-aware renaming when a variable or user-defined function is selected and the F2 button is clicked ### rename-variable.js + Purpose: Safely renames a variable in the user's code editor by: - Analyzing AST to find all matching identifiers @@ -50,12 +57,15 @@ Purpose: Safely renames a variable in the user's code editor by: - Performing in-place replacement using CodeMirror APIs ### showRenameDialog.jsx + Purpose: Opens either a dialog box to get the new variable name or a temporary box to show that the word selected cannot be renamed ## Jump to Definition -The following file allows user to jump to the definition for variables or parameters when a word is ctrl-clicked. + +The following file allows user to jump to the definition for variables or parameters when a word is ctrl-clicked. ### jumptodefinition.js + Purpose: Implements “jump to definition” for variables or parameters in the editor. How It Works: @@ -65,19 +75,23 @@ How It Works: - Moves the editor cursor to the source location of the definition ## Supporting Data Files + ### p5-instance-methods-and-creators.json + Purpose: Maps p5.js classes to: - Methods used to instantiate them (createMethods) - Methods available on those instances (methods) ### p5-scope-function-access-map.json + Purpose: Defines which p5.js functions are allowed or disallowed inside functions like setup, draw, preload, etc. ### p5-reference-functions.json + Purpose: A flat list of all available p5.js functions. Used to: - Differentiate between built-in and user-defined functions -- Filter out redefinitions or incorrect hints \ No newline at end of file +- Filter out redefinitions or incorrect hints diff --git a/contributor_docs/accessibility.md b/contributor_docs/accessibility.md index b29a7c02d5..e6bb144dfb 100644 --- a/contributor_docs/accessibility.md +++ b/contributor_docs/accessibility.md @@ -5,19 +5,19 @@ Here is a guide on [how to use the accessible editor](https://gist.github.com/Ma The code for the p5.js web editor adheres to web accessibility standards. The following guidelines will help to ensure that accessibility continues to be a priority as development continues. ## Screen Reader and Keyboard Access + **Code Structure** -* Screen Readers are an assistive technology for vision loss that helps users to navigate a web page. They are able to prioritize content based on the semantic meaning of HTML tags. Therefore, it is important to use specific tags, such as `nav`, `ul`, `li`, `section`, and so on. `div` is the least screen reader-friendly tag. For example, [here is the semantic meaning of the `body` tag](http://html5doctor.com/element-index/#body) -* All buttons/links/windows need to be accessible by the keyboard ( By tabbing, pressing space etc.) -* In cases where tags are not screen reader-friendly, we can take advantage of [tabIndex](http://webaim.org/techniques/keyboard/tabindex). Using tabIndex ensures that all elements are accessible via keyboard. [code example](https://github.com/processing/p5.js-web-editor/blob/edae248eede21d7ad7702945929efbcdfeb4d9ea/client/modules/IDE/components/Sidebar.jsx#L88) -* When opening a new window or pop up window, ensure the keyboard focus also moves to the new window. [code example](https://github.com/processing/p5.js-web-editor/blob/edae248eede21d7ad7702945929efbcdfeb4d9ea/client/modules/IDE/components/NewFileForm.jsx#L32) +- Screen Readers are an assistive technology for vision loss that helps users to navigate a web page. They are able to prioritize content based on the semantic meaning of HTML tags. Therefore, it is important to use specific tags, such as `nav`, `ul`, `li`, `section`, and so on. `div` is the least screen reader-friendly tag. For example, [here is the semantic meaning of the `body` tag](http://html5doctor.com/element-index/#body) +- All buttons/links/windows need to be accessible by the keyboard ( By tabbing, pressing space etc.) +- In cases where tags are not screen reader-friendly, we can take advantage of [tabIndex](http://webaim.org/techniques/keyboard/tabindex). Using tabIndex ensures that all elements are accessible via keyboard. [code example](https://github.com/processing/p5.js-web-editor/blob/edae248eede21d7ad7702945929efbcdfeb4d9ea/client/modules/IDE/components/Sidebar.jsx#L88) +- When opening a new window or pop up window, ensure the keyboard focus also moves to the new window. [code example](https://github.com/processing/p5.js-web-editor/blob/edae248eede21d7ad7702945929efbcdfeb4d9ea/client/modules/IDE/components/NewFileForm.jsx#L32) **Labeling** -* When creating button icons, images, or something without text (this does not include an HTML5 `