├── .changeset ├── README.md ├── calm-starfishes-thank.md └── config.json ├── .github ├── CONTRIBUTING.md ├── ISSUE_TEMPLATE │ ├── ---bug--npm-packages--.md │ ├── --bug-web-tool.md │ ├── --feature-request--npm-packages-.md │ └── --feature-web-tool.md ├── Leonardo_Logo.png ├── Leonardo_Screenshot.png ├── PULL_REQUEST_TEMPLATE.md └── workflows │ ├── ci.yml │ ├── deploy-site.yml │ └── release.yml ├── .gitignore ├── .gitmodules ├── .husky ├── .gitignore ├── commit-msg └── pre-commit ├── .lintstagedrc.json ├── .moon ├── toolchain.yml └── workspace.yml ├── .prettierignore ├── .prettierrc ├── CODE_OF_CONDUCT.md ├── LICENSE ├── README.md ├── commitlint.config.cjs ├── docs └── ui │ ├── .posthtmlrc │ ├── CHANGELOG.md │ ├── README.md │ ├── moon.yml │ ├── package.json │ └── src │ ├── APCAlookup.js │ ├── CNAME │ ├── demo.css │ ├── demo.html │ ├── demo.js │ ├── favicons │ ├── android-icon-144x144.png │ ├── android-icon-192x192.png │ ├── android-icon-36x36.png │ ├── android-icon-48x48.png │ ├── android-icon-72x72.png │ ├── android-icon-96x96.png │ ├── apple-icon-114x114.png │ ├── apple-icon-120x120.png │ ├── apple-icon-144x144.png │ ├── apple-icon-152x152.png │ ├── apple-icon-180x180.png │ ├── apple-icon-57x57.png │ ├── apple-icon-60x60.png │ ├── apple-icon-72x72.png │ ├── apple-icon-76x76.png │ ├── apple-icon-precomposed.png │ ├── apple-icon.png │ ├── browserconfig.xml │ ├── favicon-16x16.png │ ├── favicon-32x32.png │ ├── favicon-96x96.png │ ├── favicon.ico │ ├── manifest.json │ ├── ms-icon-144x144.png │ ├── ms-icon-150x150.png │ ├── ms-icon-310x310.png │ └── ms-icon-70x70.png │ ├── htmlHead.html │ ├── images │ ├── Artboard – 10.png │ ├── GitHub-Mark-120px-plus.png │ ├── GitHub-Mark.svg │ ├── HomepageImage.png │ ├── Interpolation.png │ ├── Interpolation@2x.png │ ├── Leonardo_Logo_sm.svg │ ├── adaptive_controls.png │ ├── adaptive_controls@2x.png │ ├── box_colorScales.png │ ├── box_colorScales@2x.png │ ├── box_theme.png │ ├── box_theme@2x.png │ ├── box_tools.png │ ├── box_tools@2x.png │ ├── colorspaces │ │ ├── HSL.png │ │ ├── HSV.png │ │ ├── LAB.png │ │ ├── LCH.png │ │ ├── LUV.png │ │ ├── OKLAB.png │ │ └── RGB.png │ ├── contrast-generation.png │ ├── contrast-generation@2x.png │ ├── home_CVD.png │ ├── home_analyze.png │ ├── home_compare.png │ ├── home_contrastGeneration.png │ ├── home_darkMode.png │ ├── home_designAssets.png │ ├── home_diverging.png │ ├── home_engOutput.png │ ├── home_openSource.png │ ├── home_preciseControl.png │ ├── home_userControl.png │ ├── parameters.png │ └── parameters@2x.png │ ├── index.html │ ├── index.js │ ├── js │ ├── addBulkDialog.js │ ├── addColorsFromImage.js │ ├── addFromURL.js │ ├── addLightnessBulkDialog.js │ ├── addScaleBulkDialog.js │ ├── bulkConvertDialog.js │ ├── chroma-plus.js │ ├── colorDetailsPanel.js │ ├── colorScale.js │ ├── colorScaleDiverging.js │ ├── colorScaleQualitative.js │ ├── colorScaleSequential.js │ ├── colorWheel.js │ ├── colornames.json │ ├── compareColors.js │ ├── convertColors.js │ ├── create3dModel.js │ ├── createBaseScaleOptions.js │ ├── createChart.js │ ├── createDemos.js │ ├── createHtmlElement.js │ ├── createInterpolationCharts.js │ ├── createOutputColors.js │ ├── createOutputParameters.js │ ├── createPaletteCharts.js │ ├── createPanelReportTable.js │ ├── createRGBchannelChart.js │ ├── createRatioChart.js │ ├── createSVGgradient.js │ ├── createSVGswatches.js │ ├── createSVGuiKit.js │ ├── createSamples.js │ ├── createTable.js │ ├── createXML.js │ ├── cvdColors.js │ ├── d3.js │ ├── demos │ │ ├── demo_chord.js │ │ ├── demo_choropleth.js │ │ ├── demo_density.js │ │ ├── demo_donut.js │ │ ├── demo_heatmap.js │ │ ├── demo_hexbin.js │ │ ├── demo_scatter.js │ │ ├── demo_stackedArea.js │ │ └── demo_violinJitter.js │ ├── getThemeData.js │ ├── initialDivergingScale.js │ ├── initialQualitativeScale.js │ ├── initialSequentialScale.js │ ├── initialTheme.js │ ├── keyColors.js │ ├── pageLoader.js │ ├── params.js │ ├── polarColorPath.js │ ├── popover.js │ ├── predefinedColorNames.js │ ├── ramps.js │ ├── ratios.js │ ├── scaleKeyColors.js │ ├── sliderInput.js │ ├── sortColorScales.js │ ├── tabs.js │ ├── themeTitle.js │ ├── themeUpdate.js │ ├── toast.js │ ├── toggleSwatchAttributes.js │ ├── tooltip.js │ └── utils.js │ ├── scales.html │ ├── scales.js │ ├── scss │ ├── charts.scss │ ├── colorinputs.scss │ ├── components │ │ ├── articleCard.scss │ │ ├── colorPicker.scss │ │ ├── colorSlider.scss │ │ ├── dialog.scss │ │ ├── header.scss │ │ ├── highlightCode.scss │ │ ├── imageUploader.scss │ │ ├── outputSwatches.scss │ │ ├── panelAccordion.scss │ │ ├── popover.scss │ │ ├── sections.scss │ │ ├── selectBox.scss │ │ ├── statusLabel.scss │ │ ├── textfield.scss │ │ ├── toast.scss │ │ └── tooltip.scss │ ├── converter.scss │ └── style.scss │ ├── theme.html │ ├── theme.js │ ├── tools.html │ ├── tools.js │ └── views │ ├── GithubLink.html │ ├── LogoLink.html │ ├── dialog_bulkColorConverter.html │ ├── dialog_bulkKeyColors.html │ ├── dialog_bulkLightnessStops.html │ ├── dialog_importURL.html │ ├── footer.html │ ├── header.html │ ├── header_scales.html │ ├── header_theme.html │ ├── header_tools.html │ ├── home_articles.html │ ├── home_contribute.html │ ├── home_gettingStarted.html │ ├── home_learn.html │ ├── home_main.html │ ├── home_sidenav.html │ ├── tab_accessibility.html │ ├── tab_colorCompare.html │ ├── tab_colorConverter.html │ ├── tab_contrastChecker.html │ ├── tab_divergingScale.html │ ├── tab_home.html │ ├── tab_palette.html │ ├── tab_qualitativeScale.html │ ├── tab_sequentialScale.html │ ├── tab_swatches.html │ ├── tab_theme.html │ └── toast_cvdPreview.html ├── package.json ├── packages └── contrast-colors │ ├── .eslintrc.json │ ├── .npmignore │ ├── CHANGELOG.md │ ├── README.md │ ├── index.d.ts │ ├── index.js │ ├── lib │ ├── backgroundcolor.js │ ├── chroma-plus.js │ ├── color.js │ ├── curve.js │ ├── theme.js │ └── utils.js │ ├── moon.yml │ ├── package.json │ └── test │ ├── backgroundColor.test.js │ ├── colorSetters.test.js │ ├── contrast.test.js │ ├── convertColorValue.test.js │ ├── createScale.test.js │ ├── minPositive.test.js │ ├── ratioName.test.js │ ├── searchColors.test.js │ ├── theme.test.js │ └── themeSetters.test.js ├── pnpm-lock.yaml └── pnpm-workspace.yaml /.changeset/README.md: -------------------------------------------------------------------------------- 1 | # Changesets 2 | 3 | Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works 4 | with multi-package repos, or single-package repos to help you version and publish your code. You can 5 | find the full documentation for it [in our repository](https://github.com/changesets/changesets) 6 | 7 | We have a quick list of common questions to get you started engaging with this project in 8 | [our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md) 9 | -------------------------------------------------------------------------------- /.changeset/calm-starfishes-thank.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@adobe/leonardo-ui": patch 3 | --- 4 | 5 | * Fix scales.html not loading in production 6 | -------------------------------------------------------------------------------- /.changeset/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://unpkg.com/@changesets/config@3.0.0/schema.json", 3 | "changelog": "@changesets/cli/changelog", 4 | "commit": false, 5 | "fixed": [], 6 | "linked": [], 7 | "access": "public", 8 | "baseBranch": "main", 9 | "updateInternalDependencies": "patch", 10 | "ignore": ["@adobe/leonardo-ui"] 11 | } 12 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Thanks for choosing to contribute! 4 | 5 | The following are a set of guidelines to follow when contributing to this project. 6 | 7 | ## Code Of Conduct 8 | 9 | This project adheres to the Adobe [code of conduct](../CODE_OF_CONDUCT.md). By participating, 10 | you are expected to uphold this code. Please report unacceptable behavior to 11 | [Grp-opensourceoffice@adobe.com](mailto:Grp-opensourceoffice@adobe.com). 12 | 13 | ## Have A Question? 14 | 15 | Start by filing an issue. The existing committers on this project work to reach 16 | consensus around project direction and issue solutions within issue threads 17 | (when appropriate). 18 | 19 | ## Contributor License Agreement 20 | 21 | All third-party contributions to this project must be accompanied by a signed contributor 22 | license agreement. This gives Adobe permission to redistribute your contributions 23 | as part of the project. [Sign our CLA](https://opensource.adobe.com/cla.html). You 24 | only need to submit an Adobe CLA one time, so if you have submitted one previously, 25 | you are good to go! 26 | 27 | ## Code Reviews 28 | 29 | All submissions should come in the form of pull requests and need to be reviewed 30 | by project committers. Read [GitHub's pull request documentation](https://help.github.com/articles/about-pull-requests/) 31 | for more information on sending pull requests. 32 | 33 | Lastly, please follow the [pull request template](PULL_REQUEST_TEMPLATE.md) when 34 | submitting a pull request! 35 | 36 | ## Commit Message Format 37 | 38 | Commit messages should be formatted with one of the following types: 39 | 40 | - **build**: Changes that affect the build system or external dependencies 41 | - **ci**: Changes to CI configuration files and scripts 42 | - **docs**: Documentation only changes 43 | - **feat**: A new feature 44 | - **fix**: A bug fix 45 | - **perf**: A code change that improves performance 46 | - **refactor**: A code change that neither fixes a bug nor adds a feature 47 | - **style**: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc) 48 | - **test**: Adding missing tests or correcting existing tests 49 | 50 | ## From Contributor To Committer 51 | 52 | We love contributions from our community! If you'd like to go a step beyond contributor 53 | and become a committer with full write access and a say in the project, you must 54 | be invited to the project. The existing committers employ an internal nomination 55 | process that must reach lazy consensus (silence is approval) before invitations 56 | are issued. If you feel you are qualified and want to get more deeply involved, 57 | feel free to reach out to existing committers to have a conversation about that. 58 | 59 | ## Security Issues 60 | 61 | Security issues shouldn't be reported on this issue tracker. Instead, [file an issue to our security experts](https://helpx.adobe.com/security/alertus.html) 62 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/---bug--npm-packages--.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "\U0001F41B Bug [npm packages] " 3 | about: Report a problem with the @leonardo-contrast-colors module 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | --- 8 | 9 | ## Description 10 | 11 | 12 | 13 | ## Steps to reproduce 14 | 15 | 16 | 17 | ## Expected behavior 18 | 19 | 20 | 21 | ## Screenshots 22 | 23 | 24 | 25 | ## Leonardo package and version 26 | 27 | 28 | 29 | ## Environment 30 | 31 | - **Browser(s) and OS(s):** 32 | 33 | ## Additional context 34 | 35 | 36 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/--bug-web-tool.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "\U0001F41B Bug [Web Tool] " 3 | about: Report a problem with the Leonardo web interface 4 | title: '' 5 | labels: UI, bug 6 | assignees: '' 7 | --- 8 | 9 | ## Description 10 | 11 | 12 | 13 | ## Steps to reproduce 14 | 15 | 1. Go to http://leonardocolor.io/ 16 | 2. Click on ... 17 | 3. Observe ... 18 | 19 | ## Expected behavior 20 | 21 | 22 | 23 | ## Screenshots 24 | 25 | 26 | 27 | ## Environment 28 | 29 | - **Browser(s) and OS(s):** 30 | 31 | ## Additional context 32 | 33 | 34 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/--feature-request--npm-packages-.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: '✨ Feature request [npm packages]' 3 | about: Suggest a new feature for the Leonardo npm modules 4 | title: '' 5 | labels: enhancement, npm packages 6 | assignees: '' 7 | --- 8 | 9 | ## Description 10 | 11 | 12 | 13 | ## Why do you need this feature? 14 | 15 | 16 | 17 | ## Leonardo package and version 18 | 19 | 20 | 21 | ## Additional context 22 | 23 | 24 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/--feature-web-tool.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: '✨ Feature request [Web Tool]' 3 | about: Suggest a new feature for the Leonardo web interface 4 | title: '' 5 | labels: UI, enhancement 6 | assignees: '' 7 | --- 8 | 9 | ## Description 10 | 11 | 12 | 13 | ## Why do you need this feature? 14 | 15 | 16 | 17 | ## Additional context 18 | 19 | 20 | -------------------------------------------------------------------------------- /.github/Leonardo_Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adobe/leonardo/98ac3d54f9fb4032f98c6fa4460abbdeef9a790c/.github/Leonardo_Logo.png -------------------------------------------------------------------------------- /.github/Leonardo_Screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adobe/leonardo/98ac3d54f9fb4032f98c6fa4460abbdeef9a790c/.github/Leonardo_Screenshot.png -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Description 4 | 5 | 10 | 11 | 12 | ## Motivation 13 | 14 | 15 | 16 | ## Screenshots 17 | 18 | 19 | 20 | ## To-do list 21 | 22 | 23 | 24 | - [ ] I have read the [CONTRIBUTING document](/.github/CONTRIBUTING.md). 25 | 26 | - [ ] This pull request is ready to merge. 27 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: pull_request 3 | jobs: 4 | ci: 5 | name: CI 6 | runs-on: ubuntu-latest 7 | steps: 8 | - uses: actions/checkout@v4 9 | with: 10 | fetch-depth: 0 11 | - uses: moonrepo/setup-toolchain@v0 12 | with: 13 | auto-install: true 14 | - run: moon ci 15 | - uses: 'moonrepo/run-report-action@v1' 16 | if: success() || failure() 17 | with: 18 | access-token: ${{ secrets.MOON_GH_TOKEN }} 19 | -------------------------------------------------------------------------------- /.github/workflows/deploy-site.yml: -------------------------------------------------------------------------------- 1 | name: Deploy Website 2 | 3 | on: 4 | # Runs on pushes targeting the default branch 5 | push: 6 | branches: 7 | - main 8 | 9 | # Allows you to run this workflow manually from the Actions tab 10 | workflow_dispatch: 11 | 12 | # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages 13 | permissions: 14 | contents: read 15 | pages: write 16 | id-token: write 17 | 18 | # Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. 19 | # However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. 20 | concurrency: 21 | group: 'pages' 22 | cancel-in-progress: false 23 | 24 | jobs: 25 | deploy: 26 | environment: 27 | name: github-pages 28 | url: ${{ steps.deployment.outputs.page_url }} 29 | runs-on: ubuntu-latest 30 | steps: 31 | - uses: actions/checkout@v4 32 | with: 33 | fetch-depth: 0 34 | - uses: moonrepo/setup-toolchain@v0 35 | with: 36 | auto-install: true 37 | - run: moon run ui:buildSite 38 | - name: Setup Pages 39 | uses: actions/configure-pages@v4 40 | - name: Upload artifact 41 | uses: actions/upload-pages-artifact@v3 42 | with: 43 | # Upload dist directory 44 | path: './docs/ui/dist/' 45 | - name: Deploy to GitHub Pages 46 | id: deployment 47 | uses: actions/deploy-pages@v4 48 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - beta 8 | 9 | concurrency: ${{ github.workflow }}-${{ github.ref }} 10 | 11 | jobs: 12 | release: 13 | name: Release 14 | runs-on: ubuntu-latest 15 | permissions: 16 | contents: write 17 | id-token: write 18 | steps: 19 | - uses: actions/checkout@v4 20 | with: 21 | fetch-depth: 0 22 | - uses: moonrepo/setup-toolchain@v0 23 | with: 24 | auto-install: true 25 | - run: moon setup 26 | - run: moon ci 27 | - name: Publish 28 | id: changesets 29 | uses: changesets/action@v1 30 | with: 31 | commit: 'chore: release' 32 | # This expects you to have a script called release which does a build for your packages and calls changeset publish 33 | publish: pnpm release 34 | env: 35 | GITHUB_TOKEN: ${{ secrets.MOON_GH_TOKEN }} 36 | NPM_TOKEN: ${{ secrets.ADOBE_BOT_NPM_TOKEN }} 37 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | node_modules/ 3 | npm-debug.log* 4 | .nyc_output/ 5 | .cache/ 6 | .DS_Store 7 | # moon 8 | .moon/cache 9 | .moon/docker 10 | .parcel-cache 11 | 12 | # husky 13 | .husky/_ 14 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "packages/contrast-colors/SAPC-APCA"] 2 | path = packages/contrast-colors/SAPC-APCA 3 | url = git@github.com:Myndex/SAPC-APCA.git 4 | [submodule "docs/ui/src/c3"] 5 | path = docs/ui/src/c3 6 | url = git@github.com:StanfordHCI/c3.git 7 | -------------------------------------------------------------------------------- /.husky/.gitignore: -------------------------------------------------------------------------------- 1 | _ 2 | -------------------------------------------------------------------------------- /.husky/commit-msg: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | pnpm --no-install commitlint --edit "" 5 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | pnpm run pre-commit 5 | -------------------------------------------------------------------------------- /.lintstagedrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "docs/**/*.{js,jsx,ts,tsx,json,yml,yaml,md}": ["prettier --write"], 3 | "packages/**/*.{js,jsx,ts,tsx,json,yml,yaml,md}": ["prettier --write"] 4 | } 5 | -------------------------------------------------------------------------------- /.moon/toolchain.yml: -------------------------------------------------------------------------------- 1 | # https://moonrepo.dev/docs/config/toolchain 2 | $schema: 'https://moonrepo.dev/schemas/toolchain.json' 3 | 4 | # Extend and inherit an external configuration file. Must be a valid HTTPS URL or file system path. 5 | # extends: './shared/toolchain.yml' 6 | 7 | # Configures Node.js within the toolchain. moon manages its own version of Node.js 8 | # instead of relying on a version found on the host machine. This ensures deterministic 9 | # and reproducible builds across any machine. 10 | node: 11 | # The version to use. Must be a semantic version that includes major, minor, and patch. 12 | # We suggest using the latest active LTS version: https://nodejs.org/en/about/releases 13 | version: '20.11' 14 | 15 | # The package manager to use when managing dependencies. 16 | # Accepts "npm" (default), "pnpm", or "yarn". 17 | packageManager: 'pnpm' 18 | 19 | # The version of the package manager (above) to use. 20 | pnpm: 21 | version: '9.1.1' 22 | 23 | # Add `node.version` as a constraint in the root `package.json` `engines`. 24 | addEnginesConstraint: true 25 | 26 | # Dedupe dependencies after the lockfile has changed. 27 | dedupeOnLockfileChange: true 28 | 29 | # Version format to use when syncing dependencies within the project's `package.json`. 30 | # dependencyVersionFormat: 'workspace' 31 | 32 | # Infer and automatically create moon tasks from `package.json` scripts, per project. 33 | # BEWARE: Tasks and scripts are not 1:1 in functionality, so please refer to the documentation. 34 | inferTasksFromScripts: true 35 | 36 | # Sync a project's `dependsOn` as dependencies within the project's `package.json`. 37 | syncProjectWorkspaceDependencies: true 38 | 39 | # Sync `node.version` to a 3rd-party version manager's config file. 40 | # Accepts "nodenv" (.node-version), "nvm" (.nvmrc), or none. 41 | # syncVersionManagerConfig: 'nvm' 42 | -------------------------------------------------------------------------------- /.moon/workspace.yml: -------------------------------------------------------------------------------- 1 | # https://moonrepo.dev/docs/config/workspace 2 | $schema: 'https://moonrepo.dev/schemas/workspace.json' 3 | projects: 4 | ui: 'docs/ui' 5 | contrast-colors: 'packages/contrast-colors' 6 | vcs: 7 | manager: 'git' 8 | defaultBranch: 'main' 9 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | *.min.js 3 | *.map 4 | *.snap 5 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "tabWidth": 2, 3 | "printWidth": 256, 4 | "singleQuote": true, 5 | "bracketSpacing": false, 6 | "trailingComma": "none" 7 | } 8 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Adobe Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, gender identity and expression, level of experience, 9 | nationality, personal appearance, race, religion, or sexual identity and 10 | orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | - Using welcoming and inclusive language 18 | - Being respectful of differing viewpoints and experiences 19 | - Gracefully accepting constructive criticism 20 | - Focusing on what is best for the community 21 | - Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | - The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | - Trolling, insulting/derogatory comments, and personal or political attacks 28 | - Public or private harassment 29 | - Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | - Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at Grp-opensourceoffice@adobe.com. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at [https://contributor-covenant.org/version/1/4][version] 72 | 73 | [homepage]: https://contributor-covenant.org 74 | [version]: https://contributor-covenant.org/version/1/4/ 75 | -------------------------------------------------------------------------------- /commitlint.config.cjs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2024 Adobe. All rights reserved. 3 | This file is licensed to you under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. You may obtain a copy 5 | of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | 7 | Unless required by applicable law or agreed to in writing, software distributed under 8 | the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS 9 | OF ANY KIND, either express or implied. See the License for the specific language 10 | governing permissions and limitations under the License. 11 | */ 12 | /* 13 | * For a detailed explanation regarding each configuration property, visit: 14 | * https://jestjs.io/docs/configuration 15 | */ 16 | 17 | module.exports = { 18 | extends: ['@commitlint/config-conventional'] 19 | }; 20 | -------------------------------------------------------------------------------- /docs/ui/.posthtmlrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": { 3 | "posthtml-doctype": { "doctype": "HTML 5" }, 4 | "posthtml-include": {} 5 | } 6 | } -------------------------------------------------------------------------------- /docs/ui/README.md: -------------------------------------------------------------------------------- 1 | # `@adobe/leonardo-ui` 2 | 3 | [![license](https://img.shields.io/github/license/adobe/leonardo)](https://github.com/adobe/leonardo/blob/master/LICENSE) [![Pull requests welcome](https://img.shields.io/badge/PRs-welcome-blueviolet)](https://github.com/adobe/leonardo/blob/master/.github/CONTRIBUTING.md) 4 | 5 | The Leonardo tool UI, deployed at http://www.leonardocolor.io/ 6 | 7 | ## Contributing 8 | 9 | Contributions are welcomed! Read the [Contributing Guide](../../.github/CONTRIBUTING.md) for more information. 10 | 11 | ## Development 12 | 13 | To get started developing Leonardo's UI: 14 | 15 | ```sh 16 | # Install dependencies 17 | pnpm install 18 | 19 | # Run local server 20 | pnpm moon run dev 21 | ``` 22 | 23 | Then, visit the live reloading web UIs here: 24 | http://localhost:1234/index.html 25 | http://localhost:1234/theme.html 26 | http://localhost:1234/scales.html 27 | http://localhost:1234/tools.html 28 | 29 | ### Cross-package development 30 | 31 | When making updates to `@adobe/leonardo-contrast-colors` while also developing the user interface, some issues may occur while linking the local dependency. 32 | Follow these steps **every time you install or update an npm dependency**: 33 | 34 | 1. Install your new dependency 35 | 36 | ```sh 37 | pnpm add my-new-package 38 | ``` 39 | 40 | 2. Delete the cache (if it exists) 41 | 42 | ``` 43 | rm -rf /.parcel-cache 44 | rm -rf /.moon/cache 45 | ``` 46 | 47 | 3. Link local Leonardo 48 | 49 | ```sh 50 | cd packages/contrast-colors/ 51 | pnpm link --global 52 | cd ../../ 53 | cd docs/ui/ 54 | pnpm link --global @adobe/leonardo-contrast-colors 55 | ``` 56 | 57 | If you do not properly remove the cache and re-link the local `@adobe/leonardo-contrast-colors` package, things won't work right. 58 | 59 | ## Licensing 60 | 61 | This project is licensed under the Apache V2 License. See [LICENSE](LICENSE) for more information. 62 | -------------------------------------------------------------------------------- /docs/ui/moon.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2024 Adobe. All rights reserved. 2 | # This file is licensed to you under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. You may obtain a copy 4 | # of the License at http://www.apache.org/licenses/LICENSE-2.0 5 | 6 | # Unless required by applicable law or agreed to in writing, software distributed under 7 | # the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS 8 | # OF ANY KIND, either express or implied. See the License for the specific language 9 | # governing permissions and limitations under the License. 10 | $schema: https://moonrepo.dev/schemas/project.json 11 | type: application 12 | fileGroups: 13 | sources: 14 | - 'src/**/*' 15 | output: 16 | - 'dist/**/*' 17 | dependsOn: 18 | - contrast-colors 19 | tasks: 20 | makeDistDir: 21 | command: 'mkdir -p dist' 22 | platform: system 23 | outputs: 24 | - dist 25 | dev: 26 | command: 'parcel src/index.html src/theme.html src/scales.html src/tools.html src/demo.html --no-hmr' 27 | platform: node 28 | inputs: 29 | - '@globs(sources)' 30 | local: true 31 | deps: 32 | - ~:makeDistDir 33 | - ~:copyWorkflowIcons 34 | - ~:copyUIIcons 35 | clean: 36 | command: 'rm -rf dist/*' 37 | platform: system 38 | deps: 39 | - ~:makeDistDir 40 | local: true 41 | copyWorkflowIcons: 42 | command: 43 | - cp 44 | - -r 45 | - node_modules/@adobe/spectrum-css-workflow-icons/dist/spectrum-icons.svg 46 | - dist/ 47 | platform: system 48 | deps: 49 | - ~:makeDistDir 50 | inputs: 51 | - node_modules/@adobe/spectrum-css-workflow-icons/dist/spectrum-icons.svg 52 | outputs: 53 | - dist/spectrum-icons.svg 54 | copyUIIcons: 55 | command: 56 | - cp 57 | - -r 58 | - node_modules/@spectrum-css/icon/dist/spectrum-css-icons.svg 59 | - dist/ 60 | platform: system 61 | deps: 62 | - ~:makeDistDir 63 | inputs: 64 | - node_modules/@spectrum-css/icon/dist/spectrum-css-icons.svg 65 | outputs: 66 | - dist/spectrum-css-icons.svg 67 | copyCNAME: 68 | command: 69 | - cp 70 | - -r 71 | - src/CNAME 72 | - dist/CNAME 73 | platform: system 74 | deps: 75 | - ~:makeDistDir 76 | inputs: 77 | - src/CNAME 78 | outputs: 79 | - dist/CNAME 80 | buildSite: 81 | command: 82 | - parcel 83 | - build 84 | - --no-optimize 85 | - --no-cache 86 | - src/index.html 87 | - src/scales.html 88 | - src/tools.html 89 | - src/theme.html 90 | - src/demo.html 91 | - --public-url 92 | - ./ 93 | platform: node 94 | deps: 95 | - ~:makeDistDir 96 | - ~:copyCNAME 97 | - ~:copyUIIcons 98 | - ~:copyWorkflowIcons 99 | inputs: 100 | - '@globs(sources)' 101 | outputs: 102 | - '@globs(output)' 103 | deploySite: 104 | command: 'gh-pages -d dist' 105 | platform: node 106 | local: true 107 | deps: 108 | - ~:clean 109 | - ~:buildSite 110 | -------------------------------------------------------------------------------- /docs/ui/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@adobe/leonardo-ui", 3 | "private": true, 4 | "version": "1.4.5", 5 | "description": "Demonstration UI for Leonardo", 6 | "repository": "git@github.com:adobe/leonardo.git", 7 | "author": "Nate Baldwin ", 8 | "dependencies": { 9 | "@adobe/focus-ring-polyfill": "^0.1.5", 10 | "@adobe/leonardo-contrast-colors": "workspace:^", 11 | "@adobe/spectrum-css-workflow-icons": "^1.0.0", 12 | "@bjornlu/colorblind": "^1.0.3", 13 | "@spectrum-css/actionbutton": "^1.0.4", 14 | "@spectrum-css/actiongroup": "^1.0.3", 15 | "@spectrum-css/alert": "^2.0.5", 16 | "@spectrum-css/badge": "^1.0.1", 17 | "@spectrum-css/button": "^4.0.0", 18 | "@spectrum-css/buttongroup": "^3.0.2", 19 | "@spectrum-css/checkbox": "^3.0.2", 20 | "@spectrum-css/colorhandle": "^1.0.2", 21 | "@spectrum-css/colorloupe": "^1.0.0-beta.1", 22 | "@spectrum-css/colorslider": "^1.0.2", 23 | "@spectrum-css/dialog": "^3.0.8", 24 | "@spectrum-css/divider": "^1.0.3", 25 | "@spectrum-css/dropdown": "^2.1.1", 26 | "@spectrum-css/fieldgroup": "^3.0.2", 27 | "@spectrum-css/fieldlabel": "^3.0.2", 28 | "@spectrum-css/icon": "^3.0.4", 29 | "@spectrum-css/illustratedmessage": "2.0.0", 30 | "@spectrum-css/link": "^3.0.2", 31 | "@spectrum-css/menu": "^2.1.1", 32 | "@spectrum-css/page": "^3.0.2", 33 | "@spectrum-css/picker": "^1.0.4", 34 | "@spectrum-css/popover": "^3.0.4", 35 | "@spectrum-css/progressbar": "^1.0.11", 36 | "@spectrum-css/progresscircle": "^1.0.3", 37 | "@spectrum-css/radio": "^3.0.2", 38 | "@spectrum-css/sidenav": "^3.0.2", 39 | "@spectrum-css/slider": "^3.0.2", 40 | "@spectrum-css/switch": "^1.0.3", 41 | "@spectrum-css/table": "^4.0.6", 42 | "@spectrum-css/tabs": "^2.1.1", 43 | "@spectrum-css/textfield": "^3.0.2", 44 | "@spectrum-css/toast": "^2.0.5", 45 | "@spectrum-css/tooltip": "^3.0.2", 46 | "@spectrum-css/typography": "^3.0.2", 47 | "@spectrum-css/underlay": "^2.0.10", 48 | "@spectrum-css/vars": "^4.0.0", 49 | "apca-w3": "^0.1.9", 50 | "chroma-js": "^2.4.2", 51 | "ciebase": "^0.1.1", 52 | "ciecam02": "^0.4.6", 53 | "clipboard": "^2.0.11", 54 | "color-blind": "^0.1.1", 55 | "color-names": "^2.0.0", 56 | "color.js": "^1.2.0", 57 | "d3": "^5.12.0", 58 | "d3-3d": "^0.1.2", 59 | "d3-cam02": "^0.1.5", 60 | "d3-hexbin": "^0.2.2", 61 | "d3-hsluv": "^0.1.2", 62 | "d3-hsv": "^0.1.0", 63 | "delta-e": "0.0.8", 64 | "file-saver": "^2.0.5", 65 | "fs": "0.0.1-security", 66 | "get-image-colors": "^4.0.0", 67 | "highlight.js": "^11.2.0", 68 | "hsluv": "^0.1.0", 69 | "js": "^0.1.0", 70 | "loadicons": "^1.0.0", 71 | "node-vibrant": "^3.2.1-alpha.1", 72 | "plotly.js-dist-min": "^2.5.1", 73 | "posthtml-parser": "^0.10.1", 74 | "simple-color-converter": "^2.1.13" 75 | }, 76 | "keywords": [ 77 | "accessibility", 78 | "inclusive", 79 | "wcag", 80 | "contrast", 81 | "color", 82 | "contrast-ratio", 83 | "a11y", 84 | "luminance", 85 | "relative-luminance", 86 | "accessible", 87 | "a11ycolor", 88 | "colour", 89 | "adaptive", 90 | "adaptive-color", 91 | "color-generator", 92 | "contrast-generator", 93 | "color-contrast-generator" 94 | ], 95 | "license": "Apache-2.0", 96 | "devDependencies": { 97 | "buffer": "^5.5.0||^6.0.0", 98 | "gh-pages": "^3.2.3", 99 | "highlight.js": "^11.2.0", 100 | "parcel": "^2.12.0", 101 | "path-browserify": "^1.0.0", 102 | "posthtml": "^0.16.5", 103 | "posthtml-doctype": "^1.1.1", 104 | "posthtml-include": "^1.7.2", 105 | "posthtml-modules": "^0.7.4", 106 | "process": "^0.11.10", 107 | "sass": "^1.23.6", 108 | "vm-browserify": "^1.1.2" 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /docs/ui/src/APCAlookup.js: -------------------------------------------------------------------------------- 1 | const apcaLookup = { 2 | 10: { 3 | 100: '', 4 | 200: '', 5 | 300: '', 6 | 400: '', 7 | 500: '', 8 | 600: '', 9 | 700: '', 10 | 800: '', 11 | 900: '' 12 | }, 13 | 11: { 14 | 100: '', 15 | 200: '', 16 | 300: '', 17 | 400: '', 18 | 500: '', 19 | 600: '', 20 | 700: '', 21 | 800: '', 22 | 900: '' 23 | }, 24 | 12: { 25 | 100: '', 26 | 200: '', 27 | 300: '', 28 | 400: '', 29 | 500: '', 30 | 600: '', 31 | 700: '', 32 | 800: '', 33 | 900: '' 34 | }, 35 | 14: { 36 | 100: '', 37 | 200: '', 38 | 300: '', 39 | 400: '100', 40 | 500: '90', 41 | 600: '80', 42 | 700: '60', 43 | 800: '', 44 | 900: '' 45 | }, 46 | 16: { 47 | 100: '', 48 | 200: '', 49 | 300: '100', 50 | 400: '90', 51 | 500: '80', 52 | 600: '60', 53 | 700: '55', 54 | 800: '', 55 | 900: '' 56 | }, 57 | 18: { 58 | 100: '', 59 | 200: '', 60 | 300: '90', 61 | 400: '80', 62 | 500: '60', 63 | 600: '55', 64 | 700: '50', 65 | 800: '', 66 | 900: '' 67 | }, 68 | 24: { 69 | 100: '', 70 | 200: '100', 71 | 300: '80', 72 | 400: '60', 73 | 500: '55', 74 | 600: '50', 75 | 700: '40', 76 | 800: '38', 77 | 900: '' 78 | }, 79 | 30: { 80 | 100: '', 81 | 200: '90', 82 | 300: '70', 83 | 400: '55', 84 | 500: '50', 85 | 600: '40', 86 | 700: '38', 87 | 800: '35', 88 | 900: '30' 89 | }, 90 | 36: { 91 | 100: '', 92 | 200: '80', 93 | 300: '60', 94 | 400: '50', 95 | 500: '40', 96 | 600: '38', 97 | 700: '35', 98 | 800: '30', 99 | 900: '25' 100 | }, 101 | 48: { 102 | 100: '100', 103 | 200: '70', 104 | 300: '55', 105 | 400: '40', 106 | 500: '38', 107 | 600: '35', 108 | 700: '30', 109 | 800: '25', 110 | 900: '>20' 111 | }, 112 | 60: { 113 | 100: '90', 114 | 200: '60', 115 | 300: '50', 116 | 400: '38', 117 | 500: '35', 118 | 600: '30', 119 | 700: '25', 120 | 800: '>20', 121 | 900: '>20' 122 | }, 123 | 72: { 124 | 100: '80', 125 | 200: '55', 126 | 300: '40', 127 | 400: '35', 128 | 500: '30', 129 | 600: '25', 130 | 700: '>20', 131 | 800: '>20', 132 | 900: '>20' 133 | }, 134 | 96: { 135 | 100: '70', 136 | 200: '50', 137 | 300: '35', 138 | 400: '30', 139 | 500: '25', 140 | 600: '>20', 141 | 700: '>20', 142 | 800: '>20', 143 | 900: '>20' 144 | }, 145 | 120: { 146 | 100: '60', 147 | 200: '40', 148 | 300: '30', 149 | 400: '25', 150 | 500: '>20', 151 | 600: '>20', 152 | 700: '>20', 153 | 800: '>20', 154 | 900: '>20' 155 | } 156 | }; 157 | 158 | export default apcaLookup; 159 | 160 | // var contrast = apcaLookup[fontWeight][fontSize]; 161 | -------------------------------------------------------------------------------- /docs/ui/src/CNAME: -------------------------------------------------------------------------------- 1 | leonardocolor.io 2 | -------------------------------------------------------------------------------- /docs/ui/src/favicons/android-icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adobe/leonardo/98ac3d54f9fb4032f98c6fa4460abbdeef9a790c/docs/ui/src/favicons/android-icon-144x144.png -------------------------------------------------------------------------------- /docs/ui/src/favicons/android-icon-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adobe/leonardo/98ac3d54f9fb4032f98c6fa4460abbdeef9a790c/docs/ui/src/favicons/android-icon-192x192.png -------------------------------------------------------------------------------- /docs/ui/src/favicons/android-icon-36x36.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adobe/leonardo/98ac3d54f9fb4032f98c6fa4460abbdeef9a790c/docs/ui/src/favicons/android-icon-36x36.png -------------------------------------------------------------------------------- /docs/ui/src/favicons/android-icon-48x48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adobe/leonardo/98ac3d54f9fb4032f98c6fa4460abbdeef9a790c/docs/ui/src/favicons/android-icon-48x48.png -------------------------------------------------------------------------------- /docs/ui/src/favicons/android-icon-72x72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adobe/leonardo/98ac3d54f9fb4032f98c6fa4460abbdeef9a790c/docs/ui/src/favicons/android-icon-72x72.png -------------------------------------------------------------------------------- /docs/ui/src/favicons/android-icon-96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adobe/leonardo/98ac3d54f9fb4032f98c6fa4460abbdeef9a790c/docs/ui/src/favicons/android-icon-96x96.png -------------------------------------------------------------------------------- /docs/ui/src/favicons/apple-icon-114x114.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adobe/leonardo/98ac3d54f9fb4032f98c6fa4460abbdeef9a790c/docs/ui/src/favicons/apple-icon-114x114.png -------------------------------------------------------------------------------- /docs/ui/src/favicons/apple-icon-120x120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adobe/leonardo/98ac3d54f9fb4032f98c6fa4460abbdeef9a790c/docs/ui/src/favicons/apple-icon-120x120.png -------------------------------------------------------------------------------- /docs/ui/src/favicons/apple-icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adobe/leonardo/98ac3d54f9fb4032f98c6fa4460abbdeef9a790c/docs/ui/src/favicons/apple-icon-144x144.png -------------------------------------------------------------------------------- /docs/ui/src/favicons/apple-icon-152x152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adobe/leonardo/98ac3d54f9fb4032f98c6fa4460abbdeef9a790c/docs/ui/src/favicons/apple-icon-152x152.png -------------------------------------------------------------------------------- /docs/ui/src/favicons/apple-icon-180x180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adobe/leonardo/98ac3d54f9fb4032f98c6fa4460abbdeef9a790c/docs/ui/src/favicons/apple-icon-180x180.png -------------------------------------------------------------------------------- /docs/ui/src/favicons/apple-icon-57x57.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adobe/leonardo/98ac3d54f9fb4032f98c6fa4460abbdeef9a790c/docs/ui/src/favicons/apple-icon-57x57.png -------------------------------------------------------------------------------- /docs/ui/src/favicons/apple-icon-60x60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adobe/leonardo/98ac3d54f9fb4032f98c6fa4460abbdeef9a790c/docs/ui/src/favicons/apple-icon-60x60.png -------------------------------------------------------------------------------- /docs/ui/src/favicons/apple-icon-72x72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adobe/leonardo/98ac3d54f9fb4032f98c6fa4460abbdeef9a790c/docs/ui/src/favicons/apple-icon-72x72.png -------------------------------------------------------------------------------- /docs/ui/src/favicons/apple-icon-76x76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adobe/leonardo/98ac3d54f9fb4032f98c6fa4460abbdeef9a790c/docs/ui/src/favicons/apple-icon-76x76.png -------------------------------------------------------------------------------- /docs/ui/src/favicons/apple-icon-precomposed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adobe/leonardo/98ac3d54f9fb4032f98c6fa4460abbdeef9a790c/docs/ui/src/favicons/apple-icon-precomposed.png -------------------------------------------------------------------------------- /docs/ui/src/favicons/apple-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adobe/leonardo/98ac3d54f9fb4032f98c6fa4460abbdeef9a790c/docs/ui/src/favicons/apple-icon.png -------------------------------------------------------------------------------- /docs/ui/src/favicons/browserconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | #ffffff -------------------------------------------------------------------------------- /docs/ui/src/favicons/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adobe/leonardo/98ac3d54f9fb4032f98c6fa4460abbdeef9a790c/docs/ui/src/favicons/favicon-16x16.png -------------------------------------------------------------------------------- /docs/ui/src/favicons/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adobe/leonardo/98ac3d54f9fb4032f98c6fa4460abbdeef9a790c/docs/ui/src/favicons/favicon-32x32.png -------------------------------------------------------------------------------- /docs/ui/src/favicons/favicon-96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adobe/leonardo/98ac3d54f9fb4032f98c6fa4460abbdeef9a790c/docs/ui/src/favicons/favicon-96x96.png -------------------------------------------------------------------------------- /docs/ui/src/favicons/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adobe/leonardo/98ac3d54f9fb4032f98c6fa4460abbdeef9a790c/docs/ui/src/favicons/favicon.ico -------------------------------------------------------------------------------- /docs/ui/src/favicons/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "App", 3 | "icons": [ 4 | { 5 | "src": "./android-icon-36x36.png", 6 | "sizes": "36x36", 7 | "type": "image/png", 8 | "density": "0.75" 9 | }, 10 | { 11 | "src": "./android-icon-48x48.png", 12 | "sizes": "48x48", 13 | "type": "image/png", 14 | "density": "1.0" 15 | }, 16 | { 17 | "src": "./android-icon-72x72.png", 18 | "sizes": "72x72", 19 | "type": "image/png", 20 | "density": "1.5" 21 | }, 22 | { 23 | "src": "./android-icon-96x96.png", 24 | "sizes": "96x96", 25 | "type": "image/png", 26 | "density": "2.0" 27 | }, 28 | { 29 | "src": "./android-icon-144x144.png", 30 | "sizes": "144x144", 31 | "type": "image/png", 32 | "density": "3.0" 33 | }, 34 | { 35 | "src": "./android-icon-192x192.png", 36 | "sizes": "192x192", 37 | "type": "image/png", 38 | "density": "4.0" 39 | } 40 | ] 41 | } 42 | -------------------------------------------------------------------------------- /docs/ui/src/favicons/ms-icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adobe/leonardo/98ac3d54f9fb4032f98c6fa4460abbdeef9a790c/docs/ui/src/favicons/ms-icon-144x144.png -------------------------------------------------------------------------------- /docs/ui/src/favicons/ms-icon-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adobe/leonardo/98ac3d54f9fb4032f98c6fa4460abbdeef9a790c/docs/ui/src/favicons/ms-icon-150x150.png -------------------------------------------------------------------------------- /docs/ui/src/favicons/ms-icon-310x310.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adobe/leonardo/98ac3d54f9fb4032f98c6fa4460abbdeef9a790c/docs/ui/src/favicons/ms-icon-310x310.png -------------------------------------------------------------------------------- /docs/ui/src/favicons/ms-icon-70x70.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adobe/leonardo/98ac3d54f9fb4032f98c6fa4460abbdeef9a790c/docs/ui/src/favicons/ms-icon-70x70.png -------------------------------------------------------------------------------- /docs/ui/src/htmlHead.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 13 | 14 | 15 | 16 | 17 | Leonardo 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /docs/ui/src/images/Artboard – 10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adobe/leonardo/98ac3d54f9fb4032f98c6fa4460abbdeef9a790c/docs/ui/src/images/Artboard – 10.png -------------------------------------------------------------------------------- /docs/ui/src/images/GitHub-Mark-120px-plus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adobe/leonardo/98ac3d54f9fb4032f98c6fa4460abbdeef9a790c/docs/ui/src/images/GitHub-Mark-120px-plus.png -------------------------------------------------------------------------------- /docs/ui/src/images/GitHub-Mark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /docs/ui/src/images/HomepageImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adobe/leonardo/98ac3d54f9fb4032f98c6fa4460abbdeef9a790c/docs/ui/src/images/HomepageImage.png -------------------------------------------------------------------------------- /docs/ui/src/images/Interpolation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adobe/leonardo/98ac3d54f9fb4032f98c6fa4460abbdeef9a790c/docs/ui/src/images/Interpolation.png -------------------------------------------------------------------------------- /docs/ui/src/images/Interpolation@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adobe/leonardo/98ac3d54f9fb4032f98c6fa4460abbdeef9a790c/docs/ui/src/images/Interpolation@2x.png -------------------------------------------------------------------------------- /docs/ui/src/images/Leonardo_Logo_sm.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 23 | 24 | 25 | 27 | 28 | 29 | 31 | 32 | 33 | 35 | 36 | 37 | 39 | 40 | 41 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /docs/ui/src/images/adaptive_controls.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adobe/leonardo/98ac3d54f9fb4032f98c6fa4460abbdeef9a790c/docs/ui/src/images/adaptive_controls.png -------------------------------------------------------------------------------- /docs/ui/src/images/adaptive_controls@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adobe/leonardo/98ac3d54f9fb4032f98c6fa4460abbdeef9a790c/docs/ui/src/images/adaptive_controls@2x.png -------------------------------------------------------------------------------- /docs/ui/src/images/box_colorScales.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adobe/leonardo/98ac3d54f9fb4032f98c6fa4460abbdeef9a790c/docs/ui/src/images/box_colorScales.png -------------------------------------------------------------------------------- /docs/ui/src/images/box_colorScales@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adobe/leonardo/98ac3d54f9fb4032f98c6fa4460abbdeef9a790c/docs/ui/src/images/box_colorScales@2x.png -------------------------------------------------------------------------------- /docs/ui/src/images/box_theme.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adobe/leonardo/98ac3d54f9fb4032f98c6fa4460abbdeef9a790c/docs/ui/src/images/box_theme.png -------------------------------------------------------------------------------- /docs/ui/src/images/box_theme@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adobe/leonardo/98ac3d54f9fb4032f98c6fa4460abbdeef9a790c/docs/ui/src/images/box_theme@2x.png -------------------------------------------------------------------------------- /docs/ui/src/images/box_tools.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adobe/leonardo/98ac3d54f9fb4032f98c6fa4460abbdeef9a790c/docs/ui/src/images/box_tools.png -------------------------------------------------------------------------------- /docs/ui/src/images/box_tools@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adobe/leonardo/98ac3d54f9fb4032f98c6fa4460abbdeef9a790c/docs/ui/src/images/box_tools@2x.png -------------------------------------------------------------------------------- /docs/ui/src/images/colorspaces/HSL.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adobe/leonardo/98ac3d54f9fb4032f98c6fa4460abbdeef9a790c/docs/ui/src/images/colorspaces/HSL.png -------------------------------------------------------------------------------- /docs/ui/src/images/colorspaces/HSV.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adobe/leonardo/98ac3d54f9fb4032f98c6fa4460abbdeef9a790c/docs/ui/src/images/colorspaces/HSV.png -------------------------------------------------------------------------------- /docs/ui/src/images/colorspaces/LAB.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adobe/leonardo/98ac3d54f9fb4032f98c6fa4460abbdeef9a790c/docs/ui/src/images/colorspaces/LAB.png -------------------------------------------------------------------------------- /docs/ui/src/images/colorspaces/LCH.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adobe/leonardo/98ac3d54f9fb4032f98c6fa4460abbdeef9a790c/docs/ui/src/images/colorspaces/LCH.png -------------------------------------------------------------------------------- /docs/ui/src/images/colorspaces/LUV.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adobe/leonardo/98ac3d54f9fb4032f98c6fa4460abbdeef9a790c/docs/ui/src/images/colorspaces/LUV.png -------------------------------------------------------------------------------- /docs/ui/src/images/colorspaces/OKLAB.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adobe/leonardo/98ac3d54f9fb4032f98c6fa4460abbdeef9a790c/docs/ui/src/images/colorspaces/OKLAB.png -------------------------------------------------------------------------------- /docs/ui/src/images/colorspaces/RGB.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adobe/leonardo/98ac3d54f9fb4032f98c6fa4460abbdeef9a790c/docs/ui/src/images/colorspaces/RGB.png -------------------------------------------------------------------------------- /docs/ui/src/images/contrast-generation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adobe/leonardo/98ac3d54f9fb4032f98c6fa4460abbdeef9a790c/docs/ui/src/images/contrast-generation.png -------------------------------------------------------------------------------- /docs/ui/src/images/contrast-generation@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adobe/leonardo/98ac3d54f9fb4032f98c6fa4460abbdeef9a790c/docs/ui/src/images/contrast-generation@2x.png -------------------------------------------------------------------------------- /docs/ui/src/images/home_CVD.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adobe/leonardo/98ac3d54f9fb4032f98c6fa4460abbdeef9a790c/docs/ui/src/images/home_CVD.png -------------------------------------------------------------------------------- /docs/ui/src/images/home_analyze.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adobe/leonardo/98ac3d54f9fb4032f98c6fa4460abbdeef9a790c/docs/ui/src/images/home_analyze.png -------------------------------------------------------------------------------- /docs/ui/src/images/home_compare.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adobe/leonardo/98ac3d54f9fb4032f98c6fa4460abbdeef9a790c/docs/ui/src/images/home_compare.png -------------------------------------------------------------------------------- /docs/ui/src/images/home_contrastGeneration.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adobe/leonardo/98ac3d54f9fb4032f98c6fa4460abbdeef9a790c/docs/ui/src/images/home_contrastGeneration.png -------------------------------------------------------------------------------- /docs/ui/src/images/home_darkMode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adobe/leonardo/98ac3d54f9fb4032f98c6fa4460abbdeef9a790c/docs/ui/src/images/home_darkMode.png -------------------------------------------------------------------------------- /docs/ui/src/images/home_designAssets.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adobe/leonardo/98ac3d54f9fb4032f98c6fa4460abbdeef9a790c/docs/ui/src/images/home_designAssets.png -------------------------------------------------------------------------------- /docs/ui/src/images/home_diverging.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adobe/leonardo/98ac3d54f9fb4032f98c6fa4460abbdeef9a790c/docs/ui/src/images/home_diverging.png -------------------------------------------------------------------------------- /docs/ui/src/images/home_engOutput.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adobe/leonardo/98ac3d54f9fb4032f98c6fa4460abbdeef9a790c/docs/ui/src/images/home_engOutput.png -------------------------------------------------------------------------------- /docs/ui/src/images/home_openSource.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adobe/leonardo/98ac3d54f9fb4032f98c6fa4460abbdeef9a790c/docs/ui/src/images/home_openSource.png -------------------------------------------------------------------------------- /docs/ui/src/images/home_preciseControl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adobe/leonardo/98ac3d54f9fb4032f98c6fa4460abbdeef9a790c/docs/ui/src/images/home_preciseControl.png -------------------------------------------------------------------------------- /docs/ui/src/images/home_userControl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adobe/leonardo/98ac3d54f9fb4032f98c6fa4460abbdeef9a790c/docs/ui/src/images/home_userControl.png -------------------------------------------------------------------------------- /docs/ui/src/images/parameters.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adobe/leonardo/98ac3d54f9fb4032f98c6fa4460abbdeef9a790c/docs/ui/src/images/parameters.png -------------------------------------------------------------------------------- /docs/ui/src/images/parameters@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adobe/leonardo/98ac3d54f9fb4032f98c6fa4460abbdeef9a790c/docs/ui/src/images/parameters@2x.png -------------------------------------------------------------------------------- /docs/ui/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | 23 |
24 | 25 | 26 |
27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /docs/ui/src/js/addBulkDialog.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2024 Adobe. All rights reserved. 3 | This file is licensed to you under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. You may obtain a copy 5 | of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software distributed under 7 | the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS 8 | OF ANY KIND, either express or implied. See the License for the specific language 9 | governing permissions and limitations under the License. 10 | */ 11 | 12 | import d3 from './d3'; 13 | import {addKeyColorInput} from './keyColors'; 14 | import {getColorClassById} from './getThemeData'; 15 | import {updateRamps} from './ramps'; 16 | import {updateColorDots} from './colorWheel'; 17 | 18 | function addBulk(e) { 19 | let id = e.target.parentNode.parentNode.parentNode.id.replace('-themeColor_configs', ''); 20 | 21 | let button = document.getElementById('bulkAddButton'); 22 | button.addEventListener('click', bulkItemColorInput); 23 | 24 | let dialog = document.getElementsByClassName('addBulkColorDialog'); 25 | for (let i = 0; i < dialog.length; i++) { 26 | let colorName = getColorClassById(id).name; 27 | document.getElementById('addBulkDialog_ScaleName').innerHTML = colorName; 28 | dialog[i].classList.add('is-open'); 29 | dialog[i].id = id.concat('_dialog'); 30 | } 31 | document.getElementById('dialogOverlay').style.display = 'block'; 32 | } 33 | 34 | function cancelBulk() { 35 | let dialog = document.getElementsByClassName('addBulkColorDialog'); 36 | for (let i = 0; i < dialog.length; i++) { 37 | dialog[i].classList.remove('is-open'); 38 | dialog[i].id = ' '; 39 | } 40 | document.getElementById('dialogOverlay').style.display = 'none'; 41 | } 42 | 43 | function bulkItemColorInput(e) { 44 | let id = e.target.parentNode.parentNode.parentNode.id; 45 | let itemId = id.replace('_dialog', ''); 46 | const currentColor = getColorClassById(itemId); 47 | const currentColorName = currentColor.name; 48 | const currentKeys = currentColor.colorKeys; 49 | 50 | let bulkInputs = document.getElementById('bulkColors'); 51 | let bulkValues = bulkInputs.value.replace(/\r\n/g, '\n').replace(/[,\/]/g, '\n').replace(' ', '').replace(/['\/]/g, '').replace(/["\/]/g, '').replace(' ', '').split('\n'); 52 | for (let i = 0; i < bulkValues.length; i++) { 53 | if (!bulkValues[i].startsWith('#')) { 54 | bulkValues[i] = '#' + bulkValues[i]; 55 | } 56 | } 57 | 58 | let newKeys = [...currentKeys]; 59 | // add key colors for each input 60 | for (let i = 0; i < bulkValues.length; i++) { 61 | let colorVal = d3.color(bulkValues[i]).formatHex(); 62 | addKeyColorInput(colorVal, itemId); 63 | newKeys.push(colorVal); 64 | } 65 | 66 | _theme.updateColor = {color: currentColorName, colorKeys: newKeys}; 67 | 68 | // Update gradient 69 | updateRamps(currentColor, itemId); 70 | updateColorDots(null, 'theme'); 71 | 72 | // Hide dialog 73 | cancelBulk(); 74 | // Run colorinput 75 | themeUpdateParams(); 76 | 77 | // clear inputs on close 78 | bulkInputs.value = ' '; 79 | } 80 | 81 | window.addBulk = addBulk; 82 | window.cancelBulk = cancelBulk; 83 | window.bulkItemColorInput = bulkItemColorInput; 84 | 85 | module.exports = { 86 | addBulk, 87 | bulkItemColorInput, 88 | cancelBulk 89 | }; 90 | -------------------------------------------------------------------------------- /docs/ui/src/js/addFromURL.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2024 Adobe. All rights reserved. 3 | This file is licensed to you under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. You may obtain a copy 5 | of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software distributed under 7 | the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS 8 | OF ANY KIND, either express or implied. See the License for the specific language 9 | governing permissions and limitations under the License. 10 | */ 11 | 12 | import {addColorScaleUpdate} from './colorScale'; 13 | import {sanitizeQueryString} from './utils'; 14 | 15 | function addFromURLDialog() { 16 | let button = document.getElementById('addFromURLButton'); 17 | button.addEventListener('click', addFromURL); 18 | 19 | let dialog = document.getElementById('addFromURLDialog'); 20 | dialog.classList.add('is-open'); 21 | 22 | document.getElementById('dialogOverlay').style.display = 'block'; 23 | } 24 | 25 | function cancelURL() { 26 | let dialog = document.getElementById('addFromURLDialog'); 27 | dialog.classList.remove('is-open'); 28 | 29 | document.getElementById('dialogOverlay').style.display = 'none'; 30 | } 31 | 32 | function addFromURL() { 33 | let input = document.getElementById('addFromURLinput'); 34 | let value = input.value; 35 | 36 | let url = new URL(value); 37 | let params = new URLSearchParams(sanitizeQueryString(url.search.slice(1))); 38 | let pathName = url.pathname; 39 | 40 | let crs, ratios, mode; 41 | let cName = predefinedColorNames[Math.floor(Math.random() * predefinedColorNames.length)]; 42 | 43 | // // If parameters exist, use parameter; else use default html input values 44 | if (params.has('colorKeys')) { 45 | let cr = params.get('colorKeys'); 46 | crs = cr.split(','); 47 | } 48 | 49 | if (params.has('ratios')) { 50 | // transform parameter values into array of numbers 51 | let rat = params.get('ratios'); 52 | ratios = rat.split(','); 53 | ratios = ratios.map(Number); 54 | 55 | if (ratios[0] == 0) { 56 | // if no parameter value, default to [3, 4.5] 57 | ratios = [3, 4.5]; 58 | } else { 59 | } 60 | } 61 | if (params.has('mode')) { 62 | mode = params.get('mode'); 63 | } else { 64 | // do nothing 65 | } 66 | addColorScaleUpdate(cName, crs, mode, ratios); 67 | 68 | cancelURL(); 69 | // Run colorinput 70 | // throttle(themeUpdate, 10); 71 | // Clear out value when done 72 | input.value = ' '; 73 | } 74 | 75 | window.addFromURLDialog = addFromURLDialog; 76 | window.cancelURL = cancelURL; 77 | window.addFromURL = addFromURL; 78 | 79 | module.exports = { 80 | addFromURL, 81 | addFromURLDialog, 82 | cancelURL 83 | }; 84 | -------------------------------------------------------------------------------- /docs/ui/src/js/addLightnessBulkDialog.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2024 Adobe. All rights reserved. 3 | This file is licensed to you under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. You may obtain a copy 5 | of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software distributed under 7 | the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS 8 | OF ANY KIND, either express or implied. See the License for the specific language 9 | governing permissions and limitations under the License. 10 | */ 11 | 12 | import d3 from './d3'; 13 | import * as Leo from '@adobe/leonardo-contrast-colors'; 14 | 15 | import {addRatioInputs, sortRatios} from './ratios'; 16 | import {round} from './utils'; 17 | 18 | function addLightnessBulk(e) { 19 | let dialog = document.getElementById('addBulkLightnessDialog'); 20 | dialog.classList.add('is-open'); 21 | 22 | document.getElementById('dialogOverlay').style.display = 'block'; 23 | } 24 | 25 | function cancelLightnessBulk() { 26 | let dialog = document.getElementById('addBulkLightnessDialog'); 27 | dialog.classList.remove('is-open'); 28 | 29 | document.getElementById('dialogOverlay').style.display = 'none'; 30 | } 31 | 32 | function bulkLightnessInput(e) { 33 | let bulkInputs = document.getElementById('bulkLightnessColors'); 34 | let bulkValues = bulkInputs.value.replace(/\r\n/g, '\n').replace(/[,\/]/g, '\n').replace(' ', '').replace(/['\/]/g, '').replace(/["\/]/g, '').replace(' ', '').split('\n'); 35 | for (let i = 0; i < bulkValues.length; i++) { 36 | if (!bulkValues[i].startsWith('#')) { 37 | bulkValues[i] = '#' + bulkValues[i]; 38 | } 39 | } 40 | 41 | let themeBackgroundColorArray = [d3.rgb(_theme.backgroundColorValue).r, d3.rgb(_theme.backgroundColorValue).g, d3.rgb(_theme.backgroundColorValue).b]; 42 | 43 | let contrasts = bulkValues.map((value) => { 44 | let colorArray = [d3.rgb(value).r, d3.rgb(value).g, d3.rgb(value).b]; 45 | return round(Leo.contrast(colorArray, themeBackgroundColorArray), 2); 46 | }); 47 | 48 | addRatioInputs(contrasts, bulkValues); 49 | sortRatios(); 50 | 51 | // Hide dialog 52 | cancelLightnessBulk(); 53 | // Run colorinput 54 | themeUpdateParams(); 55 | 56 | // clear inputs on close 57 | bulkInputs.value = ' '; 58 | } 59 | 60 | window.addLightnessBulk = addLightnessBulk; 61 | window.cancelLightnessBulk = cancelLightnessBulk; 62 | window.bulkLightnessInput = bulkLightnessInput; 63 | 64 | module.exports = { 65 | addLightnessBulk, 66 | bulkLightnessInput, 67 | cancelLightnessBulk 68 | }; 69 | -------------------------------------------------------------------------------- /docs/ui/src/js/createBaseScaleOptions.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2024 Adobe. All rights reserved. 3 | This file is licensed to you under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. You may obtain a copy 5 | of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software distributed under 7 | the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS 8 | OF ANY KIND, either express or implied. See the License for the specific language 9 | governing permissions and limitations under the License. 10 | */ 11 | 12 | import {getAllColorNames, getColorClassByName} from './getThemeData.js'; 13 | import {createOutputColors} from './createOutputColors'; 14 | import {createOutputParameters} from './createOutputParameters'; 15 | import {_theme} from './initialTheme'; 16 | 17 | // Create options for colors to use as base scale 18 | function baseScaleOptions() { 19 | let baseSelect = document.getElementById('themeBase'); 20 | let colorNames = getAllColorNames(); 21 | 22 | // Remove all existing options and start from scratch 23 | var i, 24 | L = baseSelect.options.length - 1; 25 | for (i = L; i >= 0; i--) { 26 | baseSelect.remove(i); 27 | } 28 | 29 | let opts = {}; 30 | for (let i = 0; i < colorNames.length; i++) { 31 | let colorname = colorNames[i]; 32 | opts[colorname] = colorname; 33 | } 34 | 35 | for (let index in opts) { 36 | baseSelect.options[baseSelect.options.length] = new Option(opts[index], index); 37 | } 38 | } 39 | 40 | let baseSelect = document.getElementById('themeBase'); 41 | baseSelect.addEventListener('change', function (e) { 42 | let colorName = `${e.target.value}`; 43 | let colorClass = getColorClassByName(colorName); 44 | _theme.backgroundColor = colorClass; 45 | 46 | createOutputColors(); 47 | createOutputParameters(); 48 | }); 49 | 50 | module.exports = { 51 | baseScaleOptions 52 | }; 53 | -------------------------------------------------------------------------------- /docs/ui/src/js/createDemos.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2024 Adobe. All rights reserved. 3 | This file is licensed to you under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. You may obtain a copy 5 | of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software distributed under 7 | the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS 8 | OF ANY KIND, either express or implied. See the License for the specific language 9 | governing permissions and limitations under the License. 10 | */ 11 | 12 | import {heatmap} from './demos/demo_heatmap'; 13 | import {choropleth} from './demos/demo_choropleth'; 14 | import {chord} from './demos/demo_chord'; 15 | import {donut} from './demos/demo_donut'; 16 | import {stackedArea} from './demos/demo_stackedArea'; 17 | import {scatter} from './demos/demo_scatter'; 18 | import {density} from './demos/demo_density'; 19 | 20 | function createDemos(scaleType, colors) { 21 | const destHeatmap = document.getElementById(`${scaleType}Heatmap`); 22 | const destChoropleth = document.getElementById(`${scaleType}Choropleth`); 23 | const destChord = document.getElementById(`${scaleType}Chord`); 24 | const destStackedArea = document.getElementById(`${scaleType}StackedArea`); 25 | const destDonut = document.getElementById(`${scaleType}Donut`); 26 | const destScatter = document.getElementById(`${scaleType}Scatter`); 27 | 28 | let dests; 29 | 30 | if (scaleType === 'qualitative') { 31 | dests = [destChord, destStackedArea, destDonut]; 32 | 33 | chord(scaleType, colors); 34 | stackedArea(scaleType, colors); 35 | donut(scaleType, colors); 36 | } else { 37 | dests = [destHeatmap, destChoropleth, destScatter]; 38 | heatmap(scaleType); 39 | scatter(scaleType); 40 | density(scaleType); 41 | choropleth(scaleType); 42 | } 43 | 44 | setTimeout(() => { 45 | for (let i = 0; i < dests.length; i++) { 46 | while (dests[i].childNodes.length > 1) { 47 | dests[i].removeChild(dests[i].firstChild); 48 | } 49 | } 50 | }, 300); 51 | } 52 | 53 | module.exports = { 54 | createDemos 55 | }; 56 | -------------------------------------------------------------------------------- /docs/ui/src/js/createHtmlElement.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2024 Adobe. All rights reserved. 3 | This file is licensed to you under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. You may obtain a copy 5 | of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software distributed under 7 | the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS 8 | OF ANY KIND, either express or implied. See the License for the specific language 9 | governing permissions and limitations under the License. 10 | */ 11 | 12 | function createHtmlElement({element, id, src, className, title, styles, type, innerHTML, attributes, eventListeners, appendTo}) { 13 | const el = document.createElement(element); 14 | if (id) el.id = id; 15 | if (className) el.className = className; 16 | if (src) el.src = src; 17 | if (styles) { 18 | for (const [prop, value] of Object.entries(styles)) { 19 | el.style[prop] = value; 20 | } 21 | } 22 | if (type) el.type = type; 23 | if (innerHTML) el.innerHTML = innerHTML; 24 | if (attributes) { 25 | for (const [prop, value] of Object.entries(attributes)) { 26 | el.setAttribute(prop, value); 27 | } 28 | } 29 | if (title) el.title = title; 30 | if (eventListeners) { 31 | for (const [event, func] of Object.entries(eventListeners)) { 32 | el.addEventListener(event, func); 33 | } 34 | } 35 | 36 | const dest = document.getElementById(appendTo); 37 | dest.appendChild(el); 38 | } 39 | 40 | function createSvgElement({element, id, className, attributes, styles, textContent, appendTo}) { 41 | const svgns = 'http://www.w3.org/2000/svg'; 42 | const el = document.createElementNS(svgns, element); 43 | if (id) el.id = id; 44 | if (className) el.setAttribute('class', className); 45 | if (styles) { 46 | for (const [prop, value] of Object.entries(styles)) { 47 | el.style[prop] = value; 48 | } 49 | } 50 | if (attributes) { 51 | for (const [prop, value] of Object.entries(attributes)) { 52 | el.setAttributeNS(null, prop, value); 53 | } 54 | } 55 | if (textContent) el.textContent = textContent; 56 | const dest = document.getElementById(appendTo); 57 | dest.appendChild(el); 58 | } 59 | 60 | module.exports = { 61 | createHtmlElement, 62 | createSvgElement 63 | }; 64 | -------------------------------------------------------------------------------- /docs/ui/src/js/createRGBchannelChart.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2024 Adobe. All rights reserved. 3 | This file is licensed to you under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. You may obtain a copy 5 | of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software distributed under 7 | the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS 8 | OF ANY KIND, either express or implied. See the License for the specific language 9 | governing permissions and limitations under the License. 10 | */ 11 | 12 | import * as d3 from './d3'; 13 | import {filterNaN} from './utils'; 14 | import {createChart} from './createChart'; 15 | 16 | function createRGBchannelChart(colors, id = 'RGBchart') { 17 | let dest = document.getElementById(id); 18 | dest.innerHTML = ' '; 19 | 20 | if (id === 'RGBchart') { 21 | colors = [...colors]; 22 | colors.push('#000000'); 23 | } else if (id === 'sequentialRGBchart' || id === 'divergingRGBchart') { 24 | colors = colors.reverse(); 25 | } 26 | 27 | // Create chart headers 28 | let RGBheader = document.createElement('h5'); 29 | RGBheader.className = 'spectrum-Typography spectrum-Heading spectrum-Heading--sizeXXS'; 30 | RGBheader.innerHTML = 'RGB channels'; 31 | dest.appendChild(RGBheader); 32 | 33 | const fillRange = (start, end) => { 34 | return Array(end + 2 - (start + 2)) 35 | .fill() 36 | .map((item, index) => start + index); 37 | }; 38 | let dataX = fillRange(1, colors.length); 39 | let sortedDataX = id === 'RGBchart' ? dataX.sort((a, b) => a - b) : dataX.sort((a, b) => b - a); 40 | 41 | let data = [ 42 | { 43 | x: sortedDataX, 44 | y: colors.map(function (d) { 45 | return filterNaN(d3.rgb(d).r); 46 | }) 47 | }, 48 | { 49 | x: sortedDataX, 50 | y: colors.map(function (d) { 51 | return filterNaN(d3.rgb(d).g); 52 | }) 53 | }, 54 | { 55 | x: sortedDataX, 56 | y: colors.map(function (d) { 57 | return filterNaN(d3.rgb(d).b); 58 | }) 59 | } 60 | ]; 61 | 62 | createChart(data, ' ', ' ', `#${id}`, 0, 255); 63 | } 64 | 65 | module.exports = {createRGBchannelChart}; 66 | -------------------------------------------------------------------------------- /docs/ui/src/js/createSVGgradient.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2024 Adobe. All rights reserved. 3 | This file is licensed to you under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. You may obtain a copy 5 | of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software distributed under 7 | the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS 8 | OF ANY KIND, either express or implied. See the License for the specific language 9 | governing permissions and limitations under the License. 10 | */ 11 | 12 | import {saveAs} from 'file-saver'; 13 | import {_theme} from './initialTheme'; 14 | import {createSvgElement} from './createHtmlElement'; 15 | 16 | function createSVGgradient(colors) { 17 | let gradientWidth = 800; 18 | let gradientHeight = 80; 19 | 20 | var svgns = 'http://www.w3.org/2000/svg'; 21 | 22 | let svgWrapper = document.createElementNS(svgns, 'svg'); 23 | svgWrapper.setAttribute('xmlns', svgns); 24 | svgWrapper.setAttribute('version', '1.1'); 25 | svgWrapper.setAttributeNS(null, 'width', gradientWidth + 'px'); 26 | svgWrapper.setAttributeNS(null, 'height', gradientHeight + 'px'); 27 | svgWrapper.setAttribute('aria-hidden', 'true'); 28 | svgWrapper.id = 'gradientSvg'; 29 | 30 | let outerElement = document.createElement('div'); 31 | outerElement.id = '_SVGgradient'; 32 | 33 | outerElement.appendChild(svgWrapper); 34 | document.body.appendChild(outerElement); 35 | 36 | createSvgElement({ 37 | element: 'rect', 38 | id: 'gradientRect', 39 | attributes: { 40 | width: gradientWidth, 41 | height: gradientHeight, 42 | fill: 'url(#gradientLinearGrad)', 43 | rx: 8 44 | }, 45 | appendTo: 'gradientSvg' 46 | }); 47 | 48 | createSvgElement({ 49 | element: 'defs', 50 | id: 'gradientDefs', 51 | appendTo: 'gradientSvg' 52 | }); 53 | 54 | createSvgElement({ 55 | element: 'linearGradient', 56 | id: 'gradientLinearGrad', 57 | attributes: { 58 | x1: 0, 59 | y1: 0, 60 | x2: gradientWidth, 61 | y2: 0, 62 | gradientUnits: 'userSpaceOnUse' 63 | }, 64 | appendTo: 'gradientDefs' 65 | }); 66 | 67 | for (let i = 0; i < colors.length; i++) { 68 | let length = colors.length - 1; 69 | 70 | // only take 10 values from scale 71 | if (Number.isInteger(i / 4)) { 72 | createSvgElement({ 73 | element: 'stop', 74 | attributes: { 75 | offset: i / length, 76 | 'stop-color': colors[i] 77 | }, 78 | appendTo: 'gradientLinearGrad' 79 | }); 80 | } 81 | } 82 | } 83 | 84 | function downloadSVGgradient(colors, mode, gradientName) { 85 | const createGradient = Promise.resolve(createSVGgradient(colors)); 86 | 87 | createGradient.then(() => { 88 | let svg = document.getElementById('_SVGgradient').innerHTML; 89 | let filename = `${gradientName}_${mode}_gradient.svg`; 90 | var blob = new Blob([`${svg}`], {type: 'image/svg+xml;charset=utf-8'}); 91 | 92 | saveAs(blob, filename); 93 | 94 | document.getElementById('_SVGgradient').remove(); 95 | }); 96 | } 97 | 98 | window.downloadSVGgradient = downloadSVGgradient; 99 | 100 | module.exports = { 101 | createSVGgradient, 102 | downloadSVGgradient 103 | }; 104 | -------------------------------------------------------------------------------- /docs/ui/src/js/createSVGswatches.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2024 Adobe. All rights reserved. 3 | This file is licensed to you under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. You may obtain a copy 5 | of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software distributed under 7 | the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS 8 | OF ANY KIND, either express or implied. See the License for the specific language 9 | governing permissions and limitations under the License. 10 | */ 11 | 12 | import {saveAs} from 'file-saver'; 13 | import {_sequentialScale} from './initialSequentialScale'; 14 | import {_divergingScale} from './initialDivergingScale'; 15 | import {_qualitativeScale} from './initialQualitativeScale'; 16 | 17 | function createSVGswatches(scaleType) { 18 | let colorClass = scaleType === 'sequential' ? _sequentialScale : scaleType === 'diverging' ? _divergingScale : _qualitativeScale; 19 | let colors = scaleType === 'qualitative' ? colorClass.keeperColors : colorClass.samples.reverse(); 20 | var svgns = 'http://www.w3.org/2000/svg'; 21 | 22 | const rectSize = 80; 23 | const marginX = 8; 24 | 25 | const swatchesPerColor = colors.length; 26 | const maxColorWidth = (rectSize + marginX) * swatchesPerColor; 27 | const maxSvgWidth = maxColorWidth; 28 | const maxSvgHeight = rectSize; 29 | 30 | let svgWrapper = document.createElementNS(svgns, 'svg'); 31 | svgWrapper.setAttribute('xmlns', svgns); 32 | svgWrapper.setAttribute('version', '1.1'); 33 | svgWrapper.setAttributeNS(null, 'width', maxSvgWidth + 'px'); 34 | svgWrapper.setAttributeNS(null, 'height', maxSvgHeight + 'px'); 35 | svgWrapper.setAttribute('aria-hidden', 'true'); 36 | svgWrapper.id = 'svg'; 37 | 38 | let outerElement = document.createElement('div'); 39 | outerElement.id = `${scaleType}SVGcolorSamples`; 40 | let y = 0; 41 | 42 | outerElement.appendChild(svgWrapper); 43 | document.body.appendChild(outerElement); 44 | 45 | for (let i = 0; i < colors.length; i++) { 46 | let x = (rectSize + marginX) * i; 47 | 48 | let rect = document.createElementNS(svgns, 'rect'); 49 | rect.setAttributeNS(null, 'x', x); 50 | rect.setAttributeNS(null, 'y', y); 51 | rect.setAttributeNS(null, 'width', rectSize); 52 | rect.setAttributeNS(null, 'height', rectSize); 53 | rect.setAttributeNS(null, 'rx', 8); 54 | rect.setAttributeNS(null, 'fill', colors[i]); 55 | svgWrapper.appendChild(rect); 56 | } 57 | } 58 | 59 | function downloadSwatches(scaleType) { 60 | const createSvg = Promise.resolve(createSVGswatches(scaleType)); 61 | 62 | createSvg.then(() => { 63 | let svg = document.getElementById(`${scaleType}SVGcolorSamples`).innerHTML; 64 | let scaleName = document.getElementById(`${scaleType}_name`).value; 65 | 66 | let filename = `${scaleName}_${scaleType}_colors.svg`; 67 | var blob = new Blob([`${svg}`], {type: 'image/svg+xml;charset=utf-8'}); 68 | 69 | saveAs(blob, filename); 70 | document.getElementById(`${scaleType}SVGcolorSamples`).remove(); 71 | }); 72 | } 73 | 74 | window.downloadSwatches = downloadSwatches; 75 | 76 | document.getElementById('downloadSequentialSwatches').addEventListener('click', () => { 77 | setTimeout(function () { 78 | downloadSwatches('sequential'); 79 | }), 80 | 1000; 81 | }); 82 | 83 | document.getElementById('downloadDivergingSwatches').addEventListener('click', () => { 84 | setTimeout(function () { 85 | downloadSwatches('diverging'); 86 | }), 87 | 1000; 88 | }); 89 | 90 | document.getElementById('downloadQualitativeSwatches').addEventListener('click', () => { 91 | setTimeout(function () { 92 | downloadSwatches('qualitative'); 93 | }), 94 | 1000; 95 | }); 96 | 97 | module.exports = { 98 | createSVGswatches, 99 | downloadSwatches 100 | }; 101 | -------------------------------------------------------------------------------- /docs/ui/src/js/createSamples.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2024 Adobe. All rights reserved. 3 | This file is licensed to you under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. You may obtain a copy 5 | of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software distributed under 7 | the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS 8 | OF ANY KIND, either express or implied. See the License for the specific language 9 | governing permissions and limitations under the License. 10 | */ 11 | 12 | import {_sequentialScale} from './initialSequentialScale'; 13 | import {_divergingScale} from './initialDivergingScale'; 14 | import {createHtmlElement} from './createHtmlElement'; 15 | import hljs from 'highlight.js/lib/core'; 16 | import javascript from 'highlight.js/lib/languages/javascript'; 17 | import css from 'highlight.js/lib/languages/css'; 18 | import {cssColorToRgb} from './utils'; 19 | hljs.registerLanguage('javascript', javascript); 20 | hljs.registerLanguage('css', css); 21 | 22 | function createSamples(samples, scaleType) { 23 | const colorClass = scaleType === 'sequential' ? _sequentialScale : _divergingScale; 24 | const originalSwatches = colorClass.swatches; 25 | const originalOutput = colorClass.output; 26 | const outputFormatPicker = document.getElementById(`${scaleType}_format`); 27 | const output = outputFormatPicker.value; 28 | const quoteSwitch = document.getElementById(`${scaleType}paramStringQuotes`); 29 | const quotes = quoteSwitch.checked; 30 | // reassign new swatch value 31 | colorClass.swatches = samples; 32 | const panelOutputContent = document.getElementById(`${scaleType}ColorScaleOutput`); 33 | panelOutputContent.innerHTML = ' '; 34 | 35 | let samplesWrapper = document.getElementById(`${scaleType}SampleSwatches`); 36 | samplesWrapper.innerHTML = ' '; 37 | 38 | let sampleColors = colorClass.colors; 39 | for (let i = 0; i < samples; i++) { 40 | createHtmlElement({ 41 | element: 'div', 42 | className: 'sampleSwatch', 43 | styles: { 44 | backgroundColor: sampleColors[i] 45 | }, 46 | appendTo: `${scaleType}SampleSwatches` 47 | }); 48 | } 49 | 50 | colorClass.output = output; 51 | sampleColors = colorClass.colors; 52 | 53 | colorClass.samples = 54 | colorClass.output === 'HEX' || colorClass.output === 'RGB' 55 | ? sampleColors 56 | : sampleColors.map((c) => { 57 | return cssColorToRgb(c); 58 | }); 59 | 60 | let colorvalueString = quotes 61 | ? sampleColors 62 | .map((c) => { 63 | return `"${c}"`; 64 | }) 65 | .toString() 66 | .replaceAll(',', ', ') 67 | : sampleColors.toString().replaceAll(',', ', '); 68 | panelOutputContent.innerHTML = colorvalueString; 69 | 70 | // Reset color class to original swatches 71 | colorClass.swatches = originalSwatches; 72 | colorClass.output = originalOutput; 73 | } 74 | 75 | module.exports = { 76 | createSamples 77 | }; 78 | -------------------------------------------------------------------------------- /docs/ui/src/js/createTable.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2024 Adobe. All rights reserved. 3 | This file is licensed to you under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. You may obtain a copy 5 | of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software distributed under 7 | the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS 8 | OF ANY KIND, either express or implied. See the License for the specific language 9 | governing permissions and limitations under the License. 10 | */ 11 | 12 | function createTable(headers, rows, destId, quiet = false) { 13 | let dest = document.getElementById(destId); 14 | 15 | let table = document.createElement('table'); 16 | table.className = quiet ? 'spectrum-Table spectrum-Table--sizeM spectrum-Table--quiet' : 'spectrum-Table spectrum-Table--sizeM'; 17 | let tHead = document.createElement('thead'); 18 | tHead.className = 'spectrum-Table-head'; 19 | let hTr = document.createElement('tr'); 20 | let tBody = document.createElement('tbody'); 21 | tBody.className = 'spectrum-Table-body'; 22 | 23 | for (let i = 0; i < headers.length; i++) { 24 | let head = document.createElement('th'); 25 | head.className = 'spectrum-Table-headCell'; 26 | head.innerHTML = headers[i]; 27 | 28 | hTr.appendChild(head); 29 | } 30 | 31 | for (let i = 0; i < rows.length; i++) { 32 | let row = document.createElement('tr'); 33 | row.className = 'spectrum-Table-row'; 34 | 35 | for (let j = 0; j < rows[i].length; j++) { 36 | let item = document.createElement('td'); 37 | item.className = 'spectrum-Table-cell'; 38 | item.innerHTML = rows[i][j]; 39 | 40 | row.appendChild(item); 41 | } 42 | 43 | tBody.appendChild(row); 44 | } 45 | 46 | tHead.appendChild(hTr); 47 | table.appendChild(tHead); 48 | table.appendChild(tBody); 49 | 50 | dest.appendChild(table); 51 | } 52 | 53 | module.exports = { 54 | createTable 55 | }; 56 | -------------------------------------------------------------------------------- /docs/ui/src/js/createXML.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2024 Adobe. All rights reserved. 3 | This file is licensed to you under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. You may obtain a copy 5 | of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software distributed under 7 | the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS 8 | OF ANY KIND, either express or implied. See the License for the specific language 9 | governing permissions and limitations under the License. 10 | */ 11 | 12 | import {saveAs} from 'file-saver'; 13 | import {_sequentialScale} from './initialSequentialScale'; 14 | import {_divergingScale} from './initialDivergingScale'; 15 | import {_qualitativeScale} from './initialQualitativeScale'; 16 | 17 | function createXML(scaleType) { 18 | let colorClass = scaleType === 'sequential' ? _sequentialScale : scaleType === 'diverging' ? _divergingScale : _qualitativeScale; 19 | let colors = scaleType === 'qualitative' ? colorClass.keeperColors : colorClass.samples.reverse(); 20 | // Type names for Tableau XML 21 | let type = scaleType === 'sequential' ? 'ordered-sequential' : scaleType === 'diverging' ? 'ordered-diverging' : 'regular'; 22 | let scaleName = document.getElementById(`${scaleType}_name`).value; 23 | 24 | let colorTags = colors.map((c) => { 25 | return `${c}`; 26 | }); 27 | let colorTagString = colorTags.toString().replaceAll(',<', '\n <'); 28 | 29 | let xml = ` 30 | 31 | 32 | 33 | 34 | ${colorTagString} 35 | 36 | 37 | `; 38 | 39 | return xml; 40 | } 41 | 42 | function downloadXML(scaleType) { 43 | const createXmlFile = Promise.resolve(createXML(scaleType)); 44 | 45 | createXmlFile.then((file) => { 46 | let scaleName = document.getElementById(`${scaleType}_name`).value; 47 | 48 | let filename = `${scaleName}_${scaleType}_colors.xml`; 49 | var blob = new Blob([`${file}`], {type: 'text/plain'}); 50 | 51 | saveAs(blob, filename); 52 | }); 53 | } 54 | 55 | window.downloadXML = downloadXML; 56 | 57 | document.getElementById('sequential_downloadXml').addEventListener('click', () => { 58 | setTimeout(function () { 59 | downloadXML('sequential'); 60 | }), 61 | 1000; 62 | }); 63 | 64 | document.getElementById('diverging_downloadXml').addEventListener('click', () => { 65 | setTimeout(function () { 66 | downloadXML('diverging'); 67 | }), 68 | 1000; 69 | }); 70 | 71 | document.getElementById('qualitative_downloadXml').addEventListener('click', () => { 72 | setTimeout(function () { 73 | downloadXML('qualitative'); 74 | }), 75 | 1000; 76 | }); 77 | 78 | module.exports = { 79 | createXML, 80 | downloadXML 81 | }; 82 | -------------------------------------------------------------------------------- /docs/ui/src/js/cvdColors.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2024 Adobe. All rights reserved. 3 | This file is licensed to you under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. You may obtain a copy 5 | of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software distributed under 7 | the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS 8 | OF ANY KIND, either express or implied. See the License for the specific language 9 | governing permissions and limitations under the License. 10 | */ 11 | 12 | import * as blinder from 'color-blind'; 13 | 14 | import d3 from './d3'; 15 | import {showToast, hideToast} from './toast'; 16 | 17 | function cvdColors(colors) { 18 | const original = colors; 19 | let cvdModeDropdown = document.getElementById('cvdMode'); 20 | let cvdMode = cvdModeDropdown.value; 21 | 22 | // if not an array 23 | if (!Array.isArray(colors)) { 24 | if (cvdMode == 'Deuteranomaly') { 25 | colors = blinder.deuteranomaly(colors); 26 | showToast(); 27 | } else if (cvdMode == 'Deuteranopia') { 28 | colors = blinder.deuteranopia(colors); 29 | showToast(); 30 | } else if (cvdMode == 'Protanomaly') { 31 | colors = blinder.protanomaly(colors); 32 | showToast(); 33 | } else if (cvdMode == 'Protanopia') { 34 | colors = blinder.protanopia(colors); 35 | showToast(); 36 | } else if (cvdMode == 'Tritanomaly') { 37 | colors = blinder.tritanomaly(colors); 38 | showToast(); 39 | } else if (cvdMode == 'Tritanopia') { 40 | colors = blinder.tritanopia(colors); 41 | showToast(); 42 | } else if (cvdMode == 'Achromatomaly') { 43 | colors = blinder.achromatomaly(colors); 44 | showToast(); 45 | } else if (cvdMode == 'Achromatopsia') { 46 | colors = blinder.achromatopsia(colors); 47 | showToast(); 48 | } else { 49 | hideToast(); 50 | } 51 | colors = d3.rgb(colors).formatRgb(); 52 | } 53 | // must be an array. 54 | else { 55 | if (cvdMode == 'Deuteranomaly') { 56 | colors = colors.map((c) => blinder.deuteranomaly(c)); 57 | } else if (cvdMode == 'Deuteranopia') { 58 | colors = colors.map((c) => blinder.deuteranopia(c)); 59 | } else if (cvdMode == 'Protanomaly') { 60 | colors = colors.map((c) => blinder.protanomaly(c)); 61 | } else if (cvdMode == 'Protanopia') { 62 | colors = colors.map((c) => blinder.protanopia(c)); 63 | } else if (cvdMode == 'Tritanomaly') { 64 | colors = colors.map((c) => blinder.tritanomaly(c)); 65 | } else if (cvdMode == 'Tritanopia') { 66 | colors = colors.map((c) => blinder.tritanopia(c)); 67 | } else if (cvdMode == 'Achromatomaly') { 68 | colors = colors.map((c) => blinder.achromatomaly(c)); 69 | } else if (cvdMode == 'Achromatopsia') { 70 | colors = colors.map((c) => blinder.achromatopsia(c)); 71 | } else { 72 | // do nothing 73 | } 74 | colors = colors.map((c) => d3.rgb(c).formatRgb()); 75 | } 76 | 77 | return colors; 78 | } 79 | 80 | module.exports = {cvdColors}; 81 | -------------------------------------------------------------------------------- /docs/ui/src/js/d3.js: -------------------------------------------------------------------------------- 1 | // import * as d3 from 'd3'; 2 | 3 | // // Import d3 plugins and add them to the d3 namespace 4 | // import * as d3cam02 from 'd3-cam02'; 5 | // import * as d3hsluv from 'd3-hsluv'; 6 | // import * as d3hsv from 'd3-hsv'; 7 | // import * as d33d from 'd3-3d'; 8 | // Object.assign(d3, d3cam02, d3hsluv, d3hsv, d33d); 9 | 10 | // module.exports = {d3}; 11 | 12 | /* 13 | Copyright 2024 Adobe. All rights reserved. 14 | This file is licensed to you under the Apache License, Version 2.0 (the "License"); 15 | you may not use this file except in compliance with the License. You may obtain a copy 16 | of the License at http://www.apache.org/licenses/LICENSE-2.0 17 | Unless required by applicable law or agreed to in writing, software distributed under 18 | the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS 19 | OF ANY KIND, either express or implied. See the License for the specific language 20 | governing permissions and limitations under the License. 21 | */ 22 | 23 | const d3 = require('d3'); 24 | const d3cam02 = require('d3-cam02'); 25 | const d3hsluv = require('d3-hsluv'); 26 | const d3hsv = require('d3-hsv'); 27 | 28 | const d3plus = { 29 | ...d3, 30 | ...d3cam02, 31 | ...d3hsluv, 32 | ...d3hsv 33 | }; 34 | 35 | d3plus.interpolateJch = (start, end) => { 36 | // constant, linear, and colorInterpolate are taken from d3-interpolate 37 | // the colorInterpolate function is `nogamma` in the d3-interpolate's color.js 38 | const constant = (x) => () => x; 39 | const linear = (a, d) => (t) => a + t * d; 40 | const colorInterpolate = (a, b) => { 41 | const d = b - a; 42 | return d ? linear(a, d) : constant(isNaN(a) ? b : a); 43 | }; 44 | 45 | start = d3plus.jch(start); 46 | end = d3plus.jch(end); 47 | 48 | const zero = Math.abs(start.h - end.h); 49 | const plus = Math.abs(start.h - (end.h + 360)); 50 | const minus = Math.abs(start.h - (end.h - 360)); 51 | if (plus < zero && plus < minus) { 52 | end.h += 360; 53 | } 54 | if (minus < zero && minus < plus) { 55 | end.h -= 360; 56 | } 57 | 58 | const startc = d3.hcl(start + '').c; 59 | const endc = d3.hcl(end + '').c; 60 | if (!startc) { 61 | start.h = end.h; 62 | } 63 | if (!endc) { 64 | end.h = start.h; 65 | } 66 | 67 | const J = colorInterpolate(start.J, end.J), 68 | C = colorInterpolate(start.C, end.C), 69 | h = colorInterpolate(start.h, end.h), 70 | opacity = colorInterpolate(start.opacity, end.opacity); 71 | 72 | return (t) => { 73 | start.J = J(t); 74 | start.C = C(t); 75 | start.h = h(t); 76 | start.opacity = opacity(t); 77 | return start + ''; 78 | }; 79 | }; 80 | 81 | module.exports = d3plus; 82 | -------------------------------------------------------------------------------- /docs/ui/src/js/demos/demo_chord.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2024 Adobe. All rights reserved. 3 | This file is licensed to you under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. You may obtain a copy 5 | of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software distributed under 7 | the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS 8 | OF ANY KIND, either express or implied. See the License for the specific language 9 | governing permissions and limitations under the License. 10 | */ 11 | 12 | import d3 from '../d3'; 13 | import {_divergingScale} from '../initialDivergingScale'; 14 | import {_sequentialScale} from '../initialSequentialScale'; 15 | 16 | function chord(scaleType, colors) { 17 | const colorClass = scaleType === 'sequential' ? _sequentialScale : _divergingScale; 18 | const originalSwatches = colorClass.swatches; 19 | colorClass.swatches = 4; 20 | 21 | const width = 250; 22 | const height = 250; 23 | const radius = 100; 24 | const outerRadius = radius + 10; 25 | 26 | // create the svg area 27 | var svg = d3 28 | .select(`#${scaleType}Chord`) 29 | .append('svg') 30 | .attr('width', width) 31 | .attr('height', height) 32 | .append('g') 33 | .attr('transform', `translate(${width / 2}, ${height / 2})`); 34 | 35 | // create a matrix 36 | var matrix = [ 37 | [0, 5871, 8916, 2868], 38 | [1951, 0, 2060, 6171], 39 | [8010, 16145, 0, 8045], 40 | [1013, 990, 940, 0] 41 | ]; 42 | 43 | // 4 groups, so create a vector of 4 colors 44 | if (!colors) colors = colorClass.colors; 45 | 46 | // give this matrix to d3.chord(): it will calculates all the info we need to draw arc and ribbon 47 | var res = d3.chord().padAngle(0.05).sortSubgroups(d3.descending)(matrix); 48 | 49 | // add the groups on the outer part of the circle 50 | svg 51 | .datum(res) 52 | .append('g') 53 | .selectAll('g') 54 | .data(function (d) { 55 | return d.groups; 56 | }) 57 | .enter() 58 | .append('g') 59 | .append('path') 60 | .style('fill', function (d, i) { 61 | return colors[i]; 62 | }) 63 | .style('stroke', 'black') 64 | .attr('d', d3.arc().innerRadius(radius).outerRadius(outerRadius)); 65 | 66 | // Add the links between groups 67 | svg 68 | .datum(res) 69 | .append('g') 70 | .selectAll('path') 71 | .data(function (d) { 72 | return d; 73 | }) 74 | .enter() 75 | .append('path') 76 | .attr('d', d3.ribbon().radius(radius)) 77 | .style('fill', function (d) { 78 | return colors[d.source.index]; 79 | }) // colors depend on the source group. Change to target otherwise. 80 | .style('stroke', 'black'); 81 | 82 | colorClass.swatches = originalSwatches; 83 | } 84 | 85 | module.exports = { 86 | chord 87 | }; 88 | -------------------------------------------------------------------------------- /docs/ui/src/js/demos/demo_choropleth.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2024 Adobe. All rights reserved. 3 | This file is licensed to you under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. You may obtain a copy 5 | of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software distributed under 7 | the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS 8 | OF ANY KIND, either express or implied. See the License for the specific language 9 | governing permissions and limitations under the License. 10 | */ 11 | 12 | import d3 from '../d3'; 13 | import {_divergingScale} from '../initialDivergingScale'; 14 | import {_sequentialScale} from '../initialSequentialScale'; 15 | 16 | function choropleth(scaleType) { 17 | const colorClass = scaleType === 'sequential' ? _sequentialScale : _divergingScale; 18 | const originalSwatches = colorClass.swatches; 19 | colorClass.swatches = 7; 20 | // The svg 21 | var margin = {top: 30, right: 30, bottom: 30, left: 30}, 22 | width = 700 - margin.left - margin.right, 23 | height = 350 - margin.top - margin.bottom; 24 | 25 | var svg = d3 26 | .select(`#${scaleType}Choropleth`) 27 | .append('svg') 28 | .attr('width', width + margin.left + margin.right) 29 | .attr('height', height + margin.top + margin.bottom) 30 | .append('g'); 31 | // .attr("transform", 32 | // "translate(" + margin.left + "," + margin.top + ")"); 33 | 34 | // Map and projection 35 | const path = d3.geoPath(); 36 | const projection = d3 37 | .geoNaturalEarth1() 38 | .scale(100) 39 | .center([0, -10]) 40 | .translate([width / 2.5, height / 1.75]); 41 | 42 | // Data and color scale 43 | let data = new Map(); 44 | const colorScale = d3.scaleThreshold().domain([100000, 1000000, 10000000, 30000000, 100000000, 500000000]).range(colorClass.colors); 45 | // const colorScale = colorClass.colorFunction; 46 | 47 | // Load external data and boot 48 | Promise.all([ 49 | d3.json('https://raw.githubusercontent.com/holtzy/D3-graph-gallery/master/DATA/world.geojson'), 50 | d3.csv('https://raw.githubusercontent.com/holtzy/D3-graph-gallery/master/DATA/world_population.csv', function (d) { 51 | data.set(d.code, +d.pop); 52 | }) 53 | ]).then(function (loadData) { 54 | let topo = loadData[0]; 55 | 56 | // Draw the map 57 | svg 58 | .append('g') 59 | .selectAll('path') 60 | .data(topo.features) 61 | .join('path') 62 | // draw each country 63 | .attr('d', d3.geoPath().projection(projection)) 64 | // set the color of each country 65 | .attr('fill', function (d) { 66 | d.total = data.get(d.id) || 0; 67 | return colorScale(d.total); 68 | }); 69 | }); 70 | 71 | colorClass.swatches = originalSwatches; 72 | } 73 | 74 | module.exports = { 75 | choropleth 76 | }; 77 | -------------------------------------------------------------------------------- /docs/ui/src/js/demos/demo_density.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2024 Adobe. All rights reserved. 3 | This file is licensed to you under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. You may obtain a copy 5 | of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software distributed under 7 | the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS 8 | OF ANY KIND, either express or implied. See the License for the specific language 9 | governing permissions and limitations under the License. 10 | */ 11 | 12 | import d3 from '../d3'; 13 | // import * as d3hexbin from 'd3-hexbin'; 14 | import {_divergingScale} from '../initialDivergingScale'; 15 | import {_sequentialScale} from '../initialSequentialScale'; 16 | // Object.assign(d3, d3hexbin); 17 | 18 | function density(scaleType) { 19 | const colorClass = scaleType === 'sequential' ? _sequentialScale : _divergingScale; 20 | 21 | // set the dimensions and margins of the graph 22 | const margin = {top: 10, right: 30, bottom: 30, left: 40}, 23 | width = 460 - margin.left - margin.right, 24 | height = 400 - margin.top - margin.bottom; 25 | 26 | // append the svg object to the body of the page 27 | const svg = d3 28 | .select(`${scaleType}Hexbin`) 29 | .append('svg') 30 | .attr('width', width + margin.left + margin.right) 31 | .attr('height', height + margin.top + margin.bottom) 32 | .append('g') 33 | .attr('transform', `translate(${margin.left},${margin.top})`); 34 | 35 | // read data 36 | d3.csv('https://raw.githubusercontent.com/holtzy/D3-graph-gallery/master/DATA/data_for_density2d.csv').then(function (data) { 37 | // Add X axis 38 | const x = d3 39 | .scaleLinear() 40 | .domain([5, 20]) 41 | .range([margin.left, width - margin.right]); 42 | svg.append('g').attr('transform', `translate(0, ${height})`).call(d3.axisBottom(x)); 43 | 44 | // Add Y axis 45 | const y = d3 46 | .scaleLinear() 47 | .domain([5, 25]) 48 | .range([height - margin.bottom, margin.top]); 49 | svg.append('g').call(d3.axisLeft(y)); 50 | 51 | // Prepare a color palette 52 | const color = d3 53 | .scaleLinear() 54 | .domain([0, 1]) // Points per square pixel. 55 | .range(['white', '#69b3a2']); 56 | 57 | // compute the density data 58 | const densityData = d3 59 | .contourDensity() 60 | .x(function (d) { 61 | return x(d.x); 62 | }) 63 | .y(function (d) { 64 | return y(d.y); 65 | }) 66 | .size([width, height]) 67 | .bandwidth(20)(data); 68 | 69 | // show the shape! 70 | svg 71 | .insert('g', 'g') 72 | .selectAll('path') 73 | .data(densityData) 74 | .enter() 75 | .append('path') 76 | .attr('d', d3.geoPath()) 77 | .attr('fill', function (d) { 78 | return color(d.value); 79 | }); 80 | }); 81 | } 82 | 83 | module.exports = { 84 | density 85 | }; 86 | -------------------------------------------------------------------------------- /docs/ui/src/js/demos/demo_donut.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2024 Adobe. All rights reserved. 3 | This file is licensed to you under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. You may obtain a copy 5 | of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software distributed under 7 | the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS 8 | OF ANY KIND, either express or implied. See the License for the specific language 9 | governing permissions and limitations under the License. 10 | */ 11 | 12 | import d3 from '../d3'; 13 | 14 | function donut(scaleType, colors) { 15 | // set the dimensions and margins of the graph 16 | var width = 250; 17 | let height = 250; 18 | let margin = 80; 19 | 20 | // The radius of the pieplot is half the width or half the height (smallest one). I subtract a bit of margin. 21 | var radius = Math.min(width, height) / 2 - margin; 22 | 23 | // append the svg object to the div called 'my_dataviz' 24 | var svg = d3 25 | .select(`#${scaleType}Donut`) 26 | .append('svg') 27 | .attr('width', width) 28 | .attr('height', height) 29 | .append('g') 30 | .attr('transform', 'translate(' + width / 2 + ',' + height / 2 + ')'); 31 | 32 | // Create dummy data 33 | var data = { 34 | a: 9, 35 | b: 18, 36 | c: 24, 37 | d: 8, 38 | e: 7, 39 | f: 5, 40 | g: 2, 41 | h: 3, 42 | i: 3 43 | }; 44 | 45 | // set the color scale 46 | var color = d3.scaleOrdinal().domain(data).range(colors); 47 | 48 | // Compute the position of each group on the pie: 49 | var pie = d3.pie().value(function (d) { 50 | return d.value; 51 | }); 52 | var data_ready = pie(d3.entries(data)); 53 | 54 | // Build the pie chart: Basically, each part of the pie is a path that we build using the arc function. 55 | svg 56 | .selectAll('whatever') 57 | .data(data_ready) 58 | .enter() 59 | .append('path') 60 | .attr( 61 | 'd', 62 | d3 63 | .arc() 64 | .innerRadius(100) // This is the size of the donut hole 65 | .outerRadius(radius) 66 | ) 67 | .attr('fill', function (d) { 68 | return color(d.data.key); 69 | }) 70 | .attr('stroke', 'black') 71 | .style('stroke-width', '1px'); 72 | } 73 | 74 | module.exports = { 75 | donut 76 | }; 77 | -------------------------------------------------------------------------------- /docs/ui/src/js/demos/demo_heatmap.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2024 Adobe. All rights reserved. 3 | This file is licensed to you under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. You may obtain a copy 5 | of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software distributed under 7 | the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS 8 | OF ANY KIND, either express or implied. See the License for the specific language 9 | governing permissions and limitations under the License. 10 | */ 11 | 12 | import d3 from '../d3'; 13 | import {_divergingScale} from '../initialDivergingScale'; 14 | import {_sequentialScale} from '../initialSequentialScale'; 15 | 16 | function heatmap(scaleType) { 17 | const colorClass = scaleType === 'sequential' ? _sequentialScale : _divergingScale; 18 | // set the dimensions and margins of the graph 19 | var margin = {top: 30, right: 30, bottom: 30, left: 30}, 20 | width = 250 - margin.left - margin.right, 21 | height = 250 - margin.top - margin.bottom; 22 | 23 | // append the svg object to the body of the page 24 | var svg = d3 25 | .select(`#${scaleType}Heatmap`) 26 | .append('svg') 27 | .attr('width', width + margin.left + margin.right) 28 | .attr('height', height + margin.top + margin.bottom) 29 | .append('g') 30 | .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); 31 | 32 | // Labels of row and columns 33 | var myGroups = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J']; 34 | var myVars = ['v1', 'v2', 'v3', 'v4', 'v5', 'v6', 'v7', 'v8', 'v9', 'v10']; 35 | 36 | // Build X scales and axis: 37 | var x = d3.scaleBand().range([0, width]).domain(myGroups).padding(0.01); 38 | svg 39 | .append('g') 40 | .attr('transform', 'translate(0,' + height + ')') 41 | .call(d3.axisBottom(x)); 42 | 43 | // Build X scales and axis: 44 | var y = d3.scaleBand().range([height, 0]).domain(myVars).padding(0.01); 45 | svg.append('g').call(d3.axisLeft(y)); 46 | 47 | colorClass.swatches = 100; 48 | var myColor = colorClass.colorFunction; 49 | 50 | d3.csv('https://raw.githubusercontent.com/holtzy/D3-graph-gallery/master/DATA/heatmap_data.csv').then(function (data) { 51 | svg 52 | .selectAll() 53 | .data(data, function (d) { 54 | return d.group + ':' + d.variable; 55 | }) 56 | .join('rect') 57 | .attr('x', function (d) { 58 | return x(d.group); 59 | }) 60 | .attr('y', function (d) { 61 | return y(d.variable); 62 | }) 63 | .attr('width', x.bandwidth()) 64 | .attr('height', y.bandwidth()) 65 | .style('fill', function (d) { 66 | return myColor(d.value).hex(); 67 | }); 68 | }); 69 | } 70 | 71 | module.exports = { 72 | heatmap 73 | }; 74 | -------------------------------------------------------------------------------- /docs/ui/src/js/demos/demo_hexbin.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2024 Adobe. All rights reserved. 3 | This file is licensed to you under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. You may obtain a copy 5 | of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software distributed under 7 | the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS 8 | OF ANY KIND, either express or implied. See the License for the specific language 9 | governing permissions and limitations under the License. 10 | */ 11 | 12 | import d3 from '../d3'; 13 | import * as d3hexbin from 'd3-hexbin'; 14 | import {_divergingScale} from '../initialDivergingScale'; 15 | import {_sequentialScale} from '../initialSequentialScale'; 16 | Object.assign(d3, d3hexbin); 17 | 18 | function hexbin(scaleType) { 19 | const colorClass = scaleType === 'sequential' ? _sequentialScale : _divergingScale; 20 | var margin = {top: 10, right: 30, bottom: 30, left: 40}, 21 | width = 460 - margin.left - margin.right, 22 | height = 400 - margin.top - margin.bottom; 23 | 24 | // append the svg object to the body of the page 25 | const svg = d3 26 | .select(`${scaleType}Hexbin`) 27 | .append('svg') 28 | .attr('width', width + margin.left + margin.right) 29 | .attr('height', height + margin.top + margin.bottom) 30 | .append('g') 31 | .attr('transform', `translate(${margin.left}, ${margin.top})`); 32 | 33 | // read data 34 | d3.csv('https://raw.githubusercontent.com/holtzy/D3-graph-gallery/master/DATA/data_for_density2d.csv').then(function (data) { 35 | // Add X axis 36 | const x = d3.scaleLinear().domain([5, 18]).range([0, width]); 37 | svg.append('g').attr('transform', `translate(0, ${height})`).call(d3.axisBottom(x)); 38 | 39 | // Add Y axis 40 | const y = d3.scaleLinear().domain([5, 20]).range([height, 0]); 41 | svg.append('g').call(d3.axisLeft(y)); 42 | 43 | // Reformat the data: d3.hexbin() needs a specific format 44 | const inputForHexbinFun = []; 45 | data.forEach(function (d) { 46 | inputForHexbinFun.push([x(d.x), y(d.y)]); // Note that we had the transform value of X and Y ! 47 | }); 48 | 49 | // Prepare a color palette 50 | const color = d3 51 | .scaleLinear() 52 | .domain([0, 600]) // Number of points in the bin? 53 | .range(['transparent', '#69b3a2']); 54 | 55 | // Compute the hexbin data 56 | const hexbin = d3 57 | .hexbin() 58 | .radius(9) // size of the bin in px 59 | .extent([ 60 | [0, 0], 61 | [width, height] 62 | ]); 63 | 64 | // Plot the hexbins 65 | svg.append('clipPath').attr('id', 'clip').append('rect').attr('width', width).attr('height', height); 66 | 67 | svg 68 | .append('g') 69 | .attr('clip-path', 'url(#clip)') 70 | .selectAll('path') 71 | .data(hexbin(inputForHexbinFun)) 72 | .join('path') 73 | .attr('d', hexbin.hexagon()) 74 | .attr('transform', function (d) { 75 | return `translate(${d.x}, ${d.y})`; 76 | }) 77 | .attr('fill', function (d) { 78 | return color(d.length); 79 | }) 80 | .attr('stroke', 'black') 81 | .attr('stroke-width', '0.1'); 82 | }); 83 | } 84 | 85 | module.exports = { 86 | hexbin 87 | }; 88 | -------------------------------------------------------------------------------- /docs/ui/src/js/demos/demo_scatter.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2024 Adobe. All rights reserved. 3 | This file is licensed to you under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. You may obtain a copy 5 | of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software distributed under 7 | the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS 8 | OF ANY KIND, either express or implied. See the License for the specific language 9 | governing permissions and limitations under the License. 10 | */ 11 | 12 | import d3 from '../d3'; 13 | import {_divergingScale} from '../initialDivergingScale'; 14 | import {_sequentialScale} from '../initialSequentialScale'; 15 | 16 | function scatter(scaleType) { 17 | const colorClass = scaleType === 'sequential' ? _sequentialScale : _divergingScale; 18 | 19 | // set the dimensions and margins of the graph 20 | var margin = {top: 30, right: 30, bottom: 30, left: 60}, 21 | width = 350 - margin.left - margin.right, 22 | height = 250 - margin.top - margin.bottom; 23 | 24 | var myColor = colorClass.colorFunction; 25 | 26 | // append the svg object to the body of the page 27 | var svg = d3 28 | .select(`#${scaleType}Scatter`) 29 | .append('svg') 30 | .attr('width', width + margin.left + margin.right) 31 | .attr('height', height + margin.top + margin.bottom) 32 | .append('g') 33 | .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); 34 | 35 | //Read the data 36 | d3.csv('https://raw.githubusercontent.com/holtzy/data_to_viz/master/Example_dataset/2_TwoNum.csv').then(function (data) { 37 | // Add X axis 38 | var x = d3.scaleLinear().domain([0, 4000]).range([0, width]); 39 | svg 40 | .append('g') 41 | .attr('transform', 'translate(0,' + height + ')') 42 | .call(d3.axisBottom(x)); 43 | 44 | // Add Y axis 45 | var y = d3.scaleLinear().domain([0, 500000]).range([height, 0]); 46 | svg.append('g').call(d3.axisLeft(y)); 47 | 48 | // Add dots 49 | svg 50 | .append('g') 51 | .selectAll('dot') 52 | .data(data) 53 | .enter() 54 | .append('circle') 55 | .attr('cx', function (d) { 56 | return x(d.GrLivArea); 57 | }) 58 | .attr('cy', function (d) { 59 | return y(d.SalePrice); 60 | }) 61 | .attr('r', 1.5) 62 | .style('fill', function (d) { 63 | return myColor(d.SalePrice / 5000); 64 | }); 65 | }); 66 | } 67 | 68 | module.exports = { 69 | scatter 70 | }; 71 | -------------------------------------------------------------------------------- /docs/ui/src/js/demos/demo_stackedArea.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2024 Adobe. All rights reserved. 3 | This file is licensed to you under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. You may obtain a copy 5 | of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software distributed under 7 | the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS 8 | OF ANY KIND, either express or implied. See the License for the specific language 9 | governing permissions and limitations under the License. 10 | */ 11 | 12 | import d3 from '../d3'; 13 | 14 | function stackedArea(scaleType, colors) { 15 | // set the dimensions and margins of the graph 16 | var margin = {top: 20, right: 30, bottom: 30, left: 55}, 17 | width = 600 - margin.left - margin.right, 18 | height = 250 - margin.top - margin.bottom; 19 | 20 | // append the svg object to the body of the page 21 | var svg = d3 22 | .select(`#${scaleType}StackedArea`) 23 | .append('svg') 24 | .attr('width', width + margin.left + margin.right) 25 | .attr('height', height + margin.top + margin.bottom) 26 | .append('g') 27 | .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); 28 | 29 | // Parse the Data 30 | d3.csv('https://raw.githubusercontent.com/holtzy/data_to_viz/master/Example_dataset/5_OneCatSevNumOrdered_wide.csv').then(function (data) { 31 | // List of groups = header of the csv files 32 | var keys = data.columns.slice(1); 33 | 34 | // Add X axis 35 | var x = d3 36 | .scaleLinear() 37 | .domain( 38 | d3.extent(data, function (d) { 39 | return d.year; 40 | }) 41 | ) 42 | .range([0, width]); 43 | svg 44 | .append('g') 45 | .attr('transform', 'translate(0,' + height + ')') 46 | .call(d3.axisBottom(x).ticks(5)); 47 | 48 | // Add Y axis 49 | var y = d3.scaleLinear().domain([0, 200000]).range([height, 0]); 50 | svg.append('g').call(d3.axisLeft(y)); 51 | 52 | // color palette 53 | var color = d3.scaleOrdinal().domain(keys).range(colors); 54 | 55 | //stack the data? 56 | var stackedData = d3.stack().keys(keys)(data); 57 | //console.log("This is the stack result: ", stackedData) 58 | 59 | // Show the areas 60 | svg 61 | .selectAll('mylayers') 62 | .data(stackedData) 63 | .enter() 64 | .append('path') 65 | .style('fill', function (d) { 66 | return color(d.key); 67 | }) 68 | .attr( 69 | 'd', 70 | d3 71 | .area() 72 | .x(function (d, i) { 73 | return x(d.data.year); 74 | }) 75 | .y0(function (d) { 76 | return y(d[0]); 77 | }) 78 | .y1(function (d) { 79 | return y(d[1]); 80 | }) 81 | ); 82 | }); 83 | } 84 | 85 | module.exports = { 86 | stackedArea 87 | }; 88 | -------------------------------------------------------------------------------- /docs/ui/src/js/getThemeData.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2024 Adobe. All rights reserved. 3 | This file is licensed to you under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. You may obtain a copy 5 | of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software distributed under 7 | the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS 8 | OF ANY KIND, either express or implied. See the License for the specific language 9 | governing permissions and limitations under the License. 10 | */ 11 | 12 | import {getLightness} from './utils'; 13 | import {_theme, _colorScales} from './initialTheme'; 14 | 15 | window.getColorClassById = getColorClassById; 16 | function getColorClassById(id) { 17 | let thisElement = document.getElementById(id); 18 | // 1. find color name from id 19 | let colorNameInput = id.concat('_colorName'); 20 | let colorName = document.getElementById(colorNameInput).value; 21 | 22 | // 2. Scrape information from the color class of the same name 23 | return getColorClassByName(colorName); 24 | } 25 | 26 | function getColorClassByName(colorName) { 27 | let currentColor = _theme.colors.filter((color) => { 28 | return color.name === colorName; 29 | }); 30 | currentColor = currentColor[0]; 31 | 32 | return currentColor; 33 | } 34 | 35 | // GET all contrast ratios 36 | function getContrastRatioInputs() { 37 | let ratioInputs = document.getElementsByClassName('ratio-Field'); 38 | let ratios = []; 39 | for (let i = 0; i < ratioInputs.length; i++) { 40 | ratios.push(ratioInputs[i].value); 41 | } 42 | return ratios; 43 | } 44 | 45 | function getThemeContrastRatios() { 46 | let theme = _theme.contrastColors; 47 | let themeRatios = theme[1].values; 48 | let ratios = []; 49 | 50 | for (let i = 0; i < themeRatios.length; i++) { 51 | const value = themeRatios[i].contrast; 52 | ratios.push(value); 53 | } 54 | 55 | return ratios; 56 | } 57 | 58 | function getLuminosities() { 59 | let theme = _theme.contrastColors; 60 | let colors = theme[1].values; 61 | let luminosities = []; 62 | 63 | for (let i = 0; i < colors.length; i++) { 64 | const value = colors[i].value; 65 | const lightness = getLightness(value); 66 | luminosities.push(lightness); 67 | } 68 | return luminosities; 69 | } 70 | 71 | function getThemeName() { 72 | // Get name 73 | let themeNameInput = document.getElementById('themeNameInput'); 74 | let themeName = themeNameInput.value; 75 | return themeName; 76 | } 77 | 78 | // GET Theme Data 79 | function getThemeData() { 80 | let baseSelectValue = _theme.backgroundColor.name; 81 | let colorScales = _theme.colors; 82 | let brightness = _theme.lightness; 83 | let contrast = _theme.contrast; 84 | 85 | return { 86 | baseScale: baseSelectValue, 87 | colorScales: colorScales, 88 | brightness: brightness, 89 | contrast: contrast 90 | }; 91 | } 92 | 93 | function getAllColorKeys() { 94 | let scales = _theme.colors; 95 | if (scales) { 96 | let colorKeys = []; 97 | scales.map((scale) => { 98 | let keys = scale.colorKeys; 99 | keys.forEach((key) => { 100 | colorKeys.push(key); 101 | }); 102 | }); 103 | 104 | return colorKeys; 105 | } else throw new Error('No color scales defined'); 106 | } 107 | 108 | function getAllColorNames() { 109 | let colors = _theme.colors; 110 | let colorNames = []; 111 | colors.forEach((color) => colorNames.push(color.name)); 112 | return colorNames; 113 | } 114 | 115 | module.exports = { 116 | getColorClassById, 117 | getContrastRatioInputs, 118 | getThemeContrastRatios, 119 | getThemeName, 120 | getThemeData, 121 | getAllColorNames, 122 | getLuminosities, 123 | getColorClassByName, 124 | getAllColorKeys 125 | }; 126 | -------------------------------------------------------------------------------- /docs/ui/src/js/initialQualitativeScale.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2024 Adobe. All rights reserved. 3 | This file is licensed to you under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. You may obtain a copy 5 | of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software distributed under 7 | the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS 8 | OF ANY KIND, either express or implied. See the License for the specific language 9 | governing permissions and limitations under the License. 10 | */ 11 | 12 | import {convertColorValue} from './utils'; 13 | const chroma = require('chroma-js'); 14 | const {extendChroma} = require('./chroma-plus'); 15 | extendChroma(chroma); 16 | 17 | class QualitativeScale { 18 | constructor({sampleColors, keeperColors, output, cvdSupport}) { 19 | this._sampleColors = sampleColors; 20 | this._keeperColors = keeperColors; 21 | this._output = output; 22 | this._cvdSupport = cvdSupport; 23 | } 24 | 25 | set sampleColors(colors) { 26 | this._sampleColors = colors; 27 | } 28 | get sampleColors() { 29 | return this._sampleColors; 30 | } 31 | 32 | set keeperColors(colors) { 33 | this._keeperColors = colors; 34 | } 35 | get keeperColors() { 36 | return this._keeperColors; 37 | } 38 | 39 | set output(output) { 40 | this._output = output; 41 | // then run all keeper colors through conversion filter 42 | let formattedColors = this._keeperColors.map((c) => { 43 | return convertColorValue(c, output); 44 | }); 45 | this._keeperColors = formattedColors; 46 | } 47 | get output() { 48 | return this._output; 49 | } 50 | 51 | set cvdSupport(cvds) { 52 | this._cvdSupport = cvds; 53 | } 54 | } 55 | 56 | let _qualitativeScale = new QualitativeScale({ 57 | sampleColors: [ 58 | '#ff7d67', 59 | '#e83326', 60 | '#ac0000', 61 | '#680000', 62 | '#f98517', 63 | '#c85b00', 64 | '#903900', 65 | '#561e01', 66 | '#c6a000', 67 | '#997600', 68 | '#6c4f00', 69 | '#412c00', 70 | '#72b622', 71 | '#4f890e', 72 | '#355e07', 73 | '#1e3604', 74 | '#33b983', 75 | '#008c5c', 76 | '#00603d', 77 | '#0e3724', 78 | '#5ba8f7', 79 | '#1077f3', 80 | '#0050ae', 81 | '#002f64', 82 | '#bf8cfc', 83 | '#9b54f3', 84 | '#7018d3', 85 | '#3d137d', 86 | '#ee74ee', 87 | '#cc34cd', 88 | '#970098', 89 | '#551153', 90 | '#ff7d67', 91 | '#e83326', 92 | '#ac0000', 93 | '#680000', 94 | '#f98517', 95 | '#c85b00', 96 | '#903900', 97 | '#561e01', 98 | '#c6a000', 99 | '#997600', 100 | '#6c4f00', 101 | '#412c00', 102 | '#72b622', 103 | '#4f890e', 104 | '#355e07', 105 | '#1e3604', 106 | '#33b983', 107 | '#008c5c', 108 | '#00603d', 109 | '#0e3724', 110 | '#5ba8f7', 111 | '#1077f3', 112 | '#0050ae', 113 | '#002f64', 114 | '#bf8cfc', 115 | '#9b54f3', 116 | '#7018d3', 117 | '#3d137d', 118 | '#ee74ee', 119 | '#cc34cd', 120 | '#970098', 121 | '#551153' 122 | ], 123 | keeperColors: [], 124 | output: 'HEX', 125 | cvdSupport: ['protanopia', 'deuteranopia', 'tritanopia', 'achromatopsia'] 126 | }); 127 | 128 | module.exports = { 129 | _qualitativeScale 130 | }; 131 | -------------------------------------------------------------------------------- /docs/ui/src/js/initialTheme.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2024 Adobe. All rights reserved. 3 | This file is licensed to you under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. You may obtain a copy 5 | of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software distributed under 7 | the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS 8 | OF ANY KIND, either express or implied. See the License for the specific language 9 | governing permissions and limitations under the License. 10 | */ 11 | 12 | import * as Leo from '@adobe/leonardo-contrast-colors'; 13 | 14 | const tempGray = new Leo.BackgroundColor({ 15 | name: 'Gray', 16 | colorKeys: ['#000000'], 17 | colorspace: 'RGB', 18 | ratios: [3.2, 4.5], 19 | output: 'HEX' 20 | }); 21 | 22 | let _theme = new Leo.Theme({ 23 | colors: [tempGray], 24 | backgroundColor: tempGray, 25 | lightness: 100, 26 | contrast: 1, 27 | saturation: 100, 28 | output: 'HEX' 29 | }); 30 | 31 | window._theme = _theme; 32 | 33 | module.exports = { 34 | tempGray, 35 | _theme 36 | }; 37 | -------------------------------------------------------------------------------- /docs/ui/src/js/pageLoader.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2024 Adobe. All rights reserved. 3 | This file is licensed to you under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. You may obtain a copy 5 | of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software distributed under 7 | the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS 8 | OF ANY KIND, either express or implied. See the License for the specific language 9 | governing permissions and limitations under the License. 10 | */ 11 | 12 | function pageLoader() { 13 | const loader = document.getElementById('pageLoader'); 14 | const page = document.getElementById('page'); 15 | setTimeout(() => { 16 | page.style.opacity = 1; 17 | }, 50); 18 | 19 | setTimeout(() => { 20 | loader.style.opacity = 0; 21 | setTimeout(() => { 22 | loader.remove(); 23 | }, 150); 24 | }, 1000); 25 | } 26 | 27 | module.exports = { 28 | pageLoader 29 | }; 30 | -------------------------------------------------------------------------------- /docs/ui/src/js/popover.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2024 Adobe. All rights reserved. 3 | This file is licensed to you under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. You may obtain a copy 5 | of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software distributed under 7 | the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS 8 | OF ANY KIND, either express or implied. See the License for the specific language 9 | governing permissions and limitations under the License. 10 | */ 11 | 12 | function togglePopover(e) { 13 | let thisId = e.target.id; 14 | let baseId; 15 | 16 | if (thisId.includes('button')) { 17 | baseId = thisId.replace('button', ''); 18 | } 19 | if (thisId.includes('close')) { 20 | baseId = thisId.replace('close', ''); 21 | } 22 | 23 | let targetId = `popover`.concat(baseId); 24 | let buttonId = `button`.concat(baseId); 25 | 26 | let button = document.getElementById(buttonId); 27 | let popover = document.getElementById(targetId); 28 | 29 | if (popover.classList.contains('is-open')) { 30 | popover.classList.remove('is-open'); 31 | button.classList.remove('is-selected'); 32 | } else { 33 | popover.classList.add('is-open'); 34 | button.classList.add('is-selected'); 35 | } 36 | 37 | // Remove open/selection states from all other buttons and popovers 38 | let popovers = document.getElementsByClassName('spectrum-Popover'); 39 | let buttons = document.getElementsByClassName('spectrum-Popover-trigger'); 40 | for (i = 0; i < popovers.length; i++) { 41 | if (popovers[i].id !== targetId) { 42 | popovers[i].classList.remove('is-open'); 43 | } 44 | } 45 | 46 | for (i = 0; i < buttons.length; i++) { 47 | if (buttons[i].id !== buttonId) { 48 | buttons[i].classList.remove('is-selected'); 49 | } 50 | } 51 | } 52 | 53 | window.togglePopover = togglePopover; 54 | 55 | document.getElementById('buttonAdaptiveControls').addEventListener('click', togglePopover); 56 | document.getElementById('closeAdaptiveControls').addEventListener('click', togglePopover); 57 | 58 | document.getElementById('buttonAnalysisColorSpace').addEventListener('click', togglePopover); 59 | document.getElementById('closeAnalysisColorSpace').addEventListener('click', togglePopover); 60 | 61 | document.getElementById('buttonShareOptions').addEventListener('click', togglePopover); 62 | document.getElementById('closeShareOptions').addEventListener('click', togglePopover); 63 | 64 | module.exports = { 65 | togglePopover 66 | }; 67 | -------------------------------------------------------------------------------- /docs/ui/src/js/predefinedColorNames.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2024 Adobe. All rights reserved. 3 | This file is licensed to you under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. You may obtain a copy 5 | of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software distributed under 7 | the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS 8 | OF ANY KIND, either express or implied. See the License for the specific language 9 | governing permissions and limitations under the License. 10 | */ 11 | import {getAllColorNames} from './getThemeData'; 12 | import {getColorDifference, capitalizeFirstLetter} from './utils'; 13 | const colorNames = require('./colornames'); 14 | 15 | const predefinedColorNames = [ 16 | 'Azure', 17 | 'Forest', 18 | 'Cerulean', 19 | 'Blue', 20 | 'Pink', 21 | 'Red', 22 | 'Indigo', 23 | 'Purple', 24 | 'Blue', 25 | 'Green', 26 | 'Crimson', 27 | 'Salmon', 28 | 'Orange', 29 | 'Tangerine', 30 | 'Yellow', 31 | 'Brown', 32 | 'Umber', 33 | 'Ochre', 34 | 'Periwinkle', 35 | 'Sage', 36 | 'Rose', 37 | 'Lavender', 38 | 'Lilac', 39 | 'Mauve', 40 | 'Mustard', 41 | 'Seafoam', 42 | 'Celery', 43 | 'Teal', 44 | 'Turquise', 45 | 'Sky', 46 | 'Gray', 47 | 'Slate' 48 | ]; 49 | 50 | function getClosestColorName(color) { 51 | let diffs = []; 52 | let keys = []; 53 | for (const [key, value] of Object.entries(colorNames)) { 54 | let colorDifference = getColorDifference(color, value); 55 | if (colorDifference < 10) { 56 | diffs.push(colorDifference); 57 | keys.push(key); 58 | } 59 | } 60 | if (diffs.length > 0) { 61 | const minDiff = Math.min(...diffs); 62 | const index = diffs.indexOf(minDiff); 63 | const closestMatchingKey = keys[index]; 64 | return capitalizeFirstLetter(closestMatchingKey); 65 | } 66 | } 67 | 68 | function getRandomColorName() { 69 | const existingColorNames = getAllColorNames(); 70 | const predefinedColorNames = Object.keys(colorNames); 71 | let colorNameOptions = predefinedColorNames.filter((item) => !existingColorNames.includes(item)); 72 | return capitalizeFirstLetter(colorNameOptions[Math.floor(Math.random() * colorNameOptions.length)]); 73 | } 74 | 75 | module.exports = { 76 | predefinedColorNames, 77 | getClosestColorName, 78 | getRandomColorName 79 | }; 80 | -------------------------------------------------------------------------------- /docs/ui/src/js/sliderInput.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2024 Adobe. All rights reserved. 3 | This file is licensed to you under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. You may obtain a copy 5 | of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software distributed under 7 | the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS 8 | OF ANY KIND, either express or implied. See the License for the specific language 9 | governing permissions and limitations under the License. 10 | */ 11 | 12 | import {createOutputColors, createDetailOutputColors} from './createOutputColors'; 13 | import {createOutputParameters} from './createOutputParameters'; 14 | import {getThemeContrastRatios, getLuminosities} from './getThemeData'; 15 | import {createRatioChart, createLuminosityChart} from './createRatioChart'; 16 | import {_theme} from './initialTheme'; 17 | import {dispatchRatioInputEvents} from './ratios'; 18 | import {round, throttle} from './utils'; 19 | 20 | function sliderValue(e) { 21 | let id = e.target.id; 22 | let slider = document.getElementById(id); 23 | let labelId = id.replace('Slider', 'Value'); 24 | let label = document.getElementById(labelId); 25 | let labelValue = labelId.includes('Contrast') ? `${round(slider.value * 100)}%` : `${slider.value}%`; 26 | label.innerHTML = labelValue; 27 | } 28 | 29 | function sliderInput(e) { 30 | let value = e.target.value; 31 | let id = e.target.id; 32 | let property = id === 'themeBrightnessSlider' ? 'lightness' : id === 'themeContrastSlider' ? 'contrast' : id === 'themeSaturationSlider' ? 'saturation' : undefined; 33 | 34 | const updateThemeClass = Promise.resolve((_theme[property] = Number(value))); 35 | updateThemeClass.then(() => { 36 | createOutputColors(); 37 | createOutputParameters(); 38 | 39 | if (document.getElementById('detailJustifiedWrapper')) { 40 | const currentColorId = document.querySelector('[id$="_colorName2"]').id; 41 | const currentColorName = document.getElementById(currentColorId).value; 42 | createDetailOutputColors(currentColorName); 43 | } 44 | 45 | const lineTypeSelect = document.getElementById('chartLineType'); 46 | const lineType = lineTypeSelect.value; 47 | let isStep = lineType === 'step' ? true : false; 48 | 49 | let chartLuminosities = Promise.resolve(getLuminosities()); 50 | chartLuminosities.then(function (resolve) { 51 | createLuminosityChart(resolve, isStep); 52 | }); 53 | 54 | let chartRatios = Promise.resolve(getThemeContrastRatios()); 55 | chartRatios.then(function (resolve) { 56 | createRatioChart(resolve, isStep); 57 | }); 58 | }); 59 | } 60 | 61 | const sliderB = document.getElementById('themeBrightnessSlider'); 62 | const sliderC = document.getElementById('themeContrastSlider'); 63 | const sliderD = document.getElementById('themeSaturationSlider'); 64 | sliderB.addEventListener('input', sliderValue); 65 | sliderB.addEventListener('input', throttle(sliderInput, 10)); 66 | sliderB.addEventListener('change', throttle(dispatchRatioInputEvents, 20)); 67 | 68 | sliderC.addEventListener('input', sliderValue); 69 | sliderC.addEventListener('input', throttle(sliderInput, 10)); 70 | 71 | sliderD.addEventListener('input', sliderValue); 72 | sliderD.addEventListener('input', throttle(sliderInput, 10)); 73 | 74 | window.sliderValue = sliderValue; 75 | window.sliderInput = sliderInput; 76 | 77 | module.exports = { 78 | sliderValue, 79 | sliderInput 80 | }; 81 | -------------------------------------------------------------------------------- /docs/ui/src/js/sortColorScales.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2024 Adobe. All rights reserved. 3 | This file is licensed to you under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. You may obtain a copy 5 | of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software distributed under 7 | the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS 8 | OF ANY KIND, either express or implied. See the License for the specific language 9 | governing permissions and limitations under the License. 10 | */ 11 | import {_theme} from './initialTheme'; 12 | import {addColorScale} from './colorScale'; 13 | import {themeUpdate} from './themeUpdate'; 14 | import {removeElementsByClass} from './utils'; 15 | const chroma = require('chroma-js'); 16 | const {extendChroma} = require('./chroma-plus'); 17 | extendChroma(chroma); 18 | 19 | window.sortColorScales = sortColorScales; 20 | function sortColorScales() { 21 | // Create an overlay to show progress 22 | const wrapper = document.getElementById('themeColorWrapper'); 23 | wrapper.style.opacity = 0.4; 24 | 25 | // Artificially pause 26 | setTimeout(() => { 27 | // For each color scale, find the average hue of all key colors 28 | // Create a new array [ { hue: 0, color: Color }, etc] 29 | // which just nests each color scale in an object containing the hue 30 | let objArr = []; 31 | for (let i = 0; i < _theme.colors.length; i++) { 32 | let currentKeys = _theme.colors[i].colorKeys; 33 | let hues = currentKeys.map((key) => { 34 | return chroma(key).jch()[2]; 35 | }); 36 | let chromas = currentKeys.map((key) => { 37 | return chroma(key).jch()[1]; 38 | }); 39 | let sumChromas = chromas.reduce((a, b) => a + b, 0); 40 | let avgChromas = sumChromas / chromas.length || 0; 41 | let sumHues = hues.reduce((a, b) => a + b, 0); 42 | let avgHues = sumHues / hues.length || 0; 43 | 44 | // Gray or near-gray should be placed at the top of 45 | // this sort function, so we force it artificially 46 | if (avgChromas < 10) avgHues = 0; 47 | 48 | // Hack to force placement of color that has hues 49 | // that cross over the 360deg threshold (ie, [1, 358]) 50 | if (Math.max(...hues) > 340 && Math.min(...hues) < 20) avgHues = 360; 51 | 52 | objArr.push({hue: avgHues, color: _theme.colors[i]}); 53 | } 54 | 55 | // Then, sort the new array by the hue key 56 | objArr.sort((a, b) => { 57 | return a.hue - b.hue; 58 | }); 59 | let sortedColors = objArr.map((item) => { 60 | return item.color; 61 | }); 62 | 63 | // Remove colors from theme before re-adding 64 | _theme.colors = []; 65 | // Then replace all DOM elements for colorscales with new ones so they're 66 | // presented in the same order as the theme has them. 67 | removeElementsByClass('themeColor_item'); 68 | for (let i = 0; i < sortedColors.length; i++) { 69 | addColorScale(sortedColors[i]); 70 | } 71 | 72 | themeUpdate(); 73 | wrapper.style.opacity = 1; 74 | }, 50); 75 | } 76 | 77 | module.exports = { 78 | sortColorScales 79 | }; 80 | -------------------------------------------------------------------------------- /docs/ui/src/js/themeTitle.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2024 Adobe. All rights reserved. 3 | This file is licensed to you under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. You may obtain a copy 5 | of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software distributed under 7 | the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS 8 | OF ANY KIND, either express or implied. See the License for the specific language 9 | governing permissions and limitations under the License. 10 | */ 11 | 12 | let themeTitleInput = document.getElementById('themeNameInput'); 13 | let themeTitleTextField = document.getElementById('themeNameTextfield'); 14 | 15 | function handleKeyUp(event) { 16 | //key code for enter 17 | if (event.keyCode === 13) { 18 | event.preventDefault(); 19 | event.target.blur(); 20 | themeTitleTextField.classList.add('spectrum-Textfield--custom'); 21 | let characters = themeTitleInput.value.length; 22 | themeTitleInput.style.width = `${characters + 4}ch`; 23 | } 24 | } 25 | 26 | themeTitleInput.addEventListener('focus', () => { 27 | themeTitleTextField.classList.remove('spectrum-Textfield--custom'); 28 | themeTitleInput.style.width = `200px`; 29 | }); 30 | themeTitleInput.addEventListener('blur', () => { 31 | themeTitleTextField.classList.add('spectrum-Textfield--custom'); 32 | let characters = themeTitleInput.value.length; 33 | themeTitleInput.style.width = `${characters + 4}ch`; 34 | }); 35 | 36 | themeTitleInput.addEventListener('keydown', (e) => { 37 | handleKeyUp(e); 38 | }); 39 | -------------------------------------------------------------------------------- /docs/ui/src/js/toast.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2024 Adobe. All rights reserved. 3 | This file is licensed to you under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. You may obtain a copy 5 | of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software distributed under 7 | the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS 8 | OF ANY KIND, either express or implied. See the License for the specific language 9 | governing permissions and limitations under the License. 10 | */ 11 | 12 | import {themeUpdate} from './themeUpdate'; 13 | 14 | function showToast() { 15 | let toast = document.getElementById('toastCVDpreview'); 16 | if (toast.classList.contains('is-visible')) { 17 | // do nothing 18 | } else { 19 | toast.classList.remove('spectrum-Exit'); 20 | toast.classList.add('spectrum-Bounce'); 21 | toast.classList.add('is-visible'); 22 | } 23 | } 24 | 25 | function hideToast() { 26 | let toast = document.getElementById('toastCVDpreview'); 27 | toast.classList.remove('spectrum-Bounce'); 28 | toast.classList.add('spectrum-Exit'); 29 | toast.classList.remove('is-visible'); 30 | } 31 | 32 | function exitPreview() { 33 | cvdModeDropdown.value = 'None'; 34 | 35 | themeUpdate(); 36 | hideToast(); 37 | } 38 | 39 | function neverShowToast() { 40 | let toast = document.getElementById('toastCVDpreview'); 41 | toast.classList.remove('spectrum-Bounce'); 42 | toast.classList.add('spectrum-Exit'); 43 | toast.classList.remove('is-visible'); 44 | toast.classList.add('hidden'); 45 | } 46 | 47 | window.showToast = showToast; 48 | window.hideToast = hideToast; 49 | window.exitPreview = exitPreview; 50 | window.neverShowToast = neverShowToast; 51 | 52 | module.exports = { 53 | showToast, 54 | hideToast, 55 | exitPreview, 56 | neverShowToast 57 | }; 58 | -------------------------------------------------------------------------------- /docs/ui/src/js/toggleSwatchAttributes.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2024 Adobe. All rights reserved. 3 | This file is licensed to you under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. You may obtain a copy 5 | of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software distributed under 7 | the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS 8 | OF ANY KIND, either express or implied. See the License for the specific language 9 | governing permissions and limitations under the License. 10 | */ 11 | 12 | function toggleSwatchContrast(e) { 13 | let on = e.target.checked; 14 | let wrapper = document.getElementById('swatchesOutputs'); 15 | 16 | if (!on) { 17 | wrapper.classList.add('hideSwatchContrast'); 18 | } else { 19 | wrapper.classList.remove('hideSwatchContrast'); 20 | } 21 | } 22 | 23 | function toggleSwatchLuminosity(e) { 24 | let on = e.target.checked; 25 | let wrapper = document.getElementById('swatchesOutputs'); 26 | 27 | if (!on) { 28 | wrapper.classList.add('hideSwatchLuminosity'); 29 | } else { 30 | wrapper.classList.remove('hideSwatchLuminosity'); 31 | } 32 | } 33 | 34 | window.toggleSwatchContrast = toggleSwatchContrast; 35 | window.toggleSwatchLuminosity = toggleSwatchLuminosity; 36 | 37 | module.exports = { 38 | toggleSwatchContrast, 39 | toggleSwatchLuminosity 40 | }; 41 | -------------------------------------------------------------------------------- /docs/ui/src/js/tooltip.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2024 Adobe. All rights reserved. 3 | This file is licensed to you under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. You may obtain a copy 5 | of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software distributed under 7 | the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS 8 | OF ANY KIND, either express or implied. See the License for the specific language 9 | governing permissions and limitations under the License. 10 | */ 11 | 12 | function toggleTooltip(targetId) { 13 | let tooltip = document.getElementById(targetId); 14 | if (!tooltip.classList.contains('is-open')) { 15 | tooltip.classList.add('is-open'); 16 | } else { 17 | tooltip.classList.remove('is-open'); 18 | } 19 | } 20 | 21 | window.toggleTooltip = toggleTooltip; 22 | 23 | module.exports = {toggleTooltip}; 24 | -------------------------------------------------------------------------------- /docs/ui/src/scales.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 | 25 |
26 | 27 | 28 | 29 | 32 | 33 | 34 | 35 | 36 | 37 |
38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /docs/ui/src/scss/colorinputs.scss: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2024 Adobe. All rights reserved. 3 | This file is licensed to you under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. You may obtain a copy 5 | of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | 7 | Unless required by applicable law or agreed to in writing, software distributed under 8 | the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS 9 | OF ANY KIND, either express or implied. See the License for the specific language 10 | governing permissions and limitations under the License. 11 | */ 12 | 13 | input[type='color'] { 14 | -webkit-appearance: none; 15 | height: 32px; 16 | width: 32px; 17 | border: 0; 18 | padding: 0; 19 | margin: 0; 20 | background-color: transparent; 21 | border: none; 22 | border-collapse: collapse; 23 | outline: none; 24 | border-radius: 4px; 25 | 26 | &.spectrum-Textfield-swatch { 27 | margin-top: var(--spectrum-global-dimension-size-100); 28 | margin-left: var(--spectrum-global-dimension-size-100); 29 | } 30 | } 31 | input[type='color']::-webkit-color-swatch-wrapper { 32 | padding: 0px; 33 | border: none; 34 | } 35 | input[type='color']::-webkit-color-swatch { 36 | border: none; 37 | border-radius: 4px; 38 | } 39 | input[type='color']:disabled { 40 | // opacity: 0.4; 41 | border-color: var(--spectrum-global-color-gray-200); 42 | } 43 | 44 | .slider:focus, 45 | input[type='color']:focus { 46 | outline: none; 47 | border: 1px solid var(--spectrum-alias-background-color-default); 48 | box-shadow: 0 0 0 2px var(--spectrum-alias-focus-color); 49 | } 50 | 51 | input[type='color']::-webkit-color-swatch { 52 | border-radius: 4px; 53 | border: 1px solid rgba(0, 0, 0, 0.25); 54 | } 55 | input[type='color']::-moz-color-swatch { 56 | border-radius: 4px; 57 | border: 1px solid rgba(0, 0, 0, 0.25); 58 | } 59 | 60 | // Color Input Classes 61 | .keyColor > input[type='color'] { 62 | border-top-right-radius: 0; 63 | border-bottom-right-radius: 0; 64 | } 65 | .keyColor > input[type='color']::-webkit-color-swatch { 66 | border-top-right-radius: 0; 67 | border-bottom-right-radius: 0; 68 | } 69 | .keyColor > input[type='color']::-moz-color-swatch { 70 | border-top-right-radius: 0; 71 | border-bottom-right-radius: 0; 72 | } 73 | input[type='color'].keyColor-Item + .spectrum-ActionButton { 74 | border-top-left-radius: 0; 75 | border-bottom-left-radius: 0; 76 | } 77 | 78 | // Middle color for diverging needs full rounding 79 | .keyColor-diverging-middle > input[type='color'] { 80 | border-top-right-radius: 4px; 81 | border-bottom-right-radius: 4px; 82 | } 83 | .keyColor-diverging-middle > input[type='color']::-webkit-color-swatch { 84 | border-top-right-radius: 4px; 85 | border-bottom-right-radius: 4px; 86 | } 87 | .keyColor-diverging-middle > input[type='color']::-moz-color-swatch { 88 | border-top-right-radius: 4px; 89 | border-bottom-right-radius: 4px; 90 | } 91 | 92 | .spectrum-FieldLabel--right { 93 | padding: var(--spectrum-fieldlabel-side-padding-top, var(--spectrum-global-dimension-size-100)) 0 0 var(--spectrum-fieldlabel-side-padding-x, var(--spectrum-global-dimension-size-100)); 94 | } 95 | -------------------------------------------------------------------------------- /docs/ui/src/scss/components/articleCard.scss: -------------------------------------------------------------------------------- 1 | .articleCards-Wrapper { 2 | display: flex; 3 | flex-direction: row; 4 | flex-wrap: wrap; 5 | gap: var(--spectrum-global-dimension-size-200); 6 | } 7 | 8 | .articleCard { 9 | display: flex; 10 | flex-direction: column; 11 | align-items: flex-start; 12 | border-radius: var(--spectrum-alias-border-radius-medium); 13 | border-width: 1px; 14 | border-style: solid; 15 | border-color: var(--spectrum-global-color-gray-300); 16 | background-color: var(--spectrum-global-color-gray-75); 17 | flex-shrink: 1; 18 | min-width: 240px; 19 | width: 100%; 20 | max-width: 360px; 21 | text-decoration: none; 22 | transition: 23 | border-color var(--spectrum-global-animation-duration-100, 130ms) ease-out, 24 | background-color var(--spectrum-global-animation-duration-100, 130ms) ease-out; 25 | 26 | &:hover { 27 | border-color: var(--spectrum-global-color-gray-400); 28 | background-color: var(--spectrum-global-color-gray-50); 29 | } 30 | &:active { 31 | border-color: var(--spectrum-global-color-gray-500); 32 | background-color: var(--spectrum-global-color-gray-50); 33 | } 34 | } 35 | 36 | .articleCard_content { 37 | padding: 0 var(--spectrum-global-dimension-size-300) var(--spectrum-global-dimension-size-300); 38 | } 39 | 40 | .articleCard_image { 41 | width: 100%; 42 | height: 100px; 43 | margin: 0; 44 | border-top-left-radius: var(--spectrum-alias-border-radius-medium); 45 | border-top-right-radius: var(--spectrum-alias-border-radius-medium); 46 | object-fit: cover; 47 | } 48 | 49 | .spectrum-Body.articleCard_ref { 50 | margin-bottom: 0; 51 | font-style: italic; 52 | color: var(--spectrum-global-color-gray-700); 53 | } 54 | -------------------------------------------------------------------------------- /docs/ui/src/scss/components/colorPicker.scss: -------------------------------------------------------------------------------- 1 | .colorPicker { 2 | height: 32px; 3 | width: 32px; 4 | overflow: visible; 5 | border-radius: var(--spectrum-alias-border-radius-regular); 6 | background-color: rgba(0, 0, 0, 0.15); 7 | position: relative; 8 | z-index: 1; 9 | } 10 | 11 | input[type='color'].colorPicker-Input { 12 | display: none; 13 | z-index: -1; 14 | } 15 | 16 | .colorPicker-Popover { 17 | padding: var(--spectrum-global-dimension-size-150); 18 | top: 38px; 19 | left: 0; 20 | width: 200px; 21 | } 22 | -------------------------------------------------------------------------------- /docs/ui/src/scss/components/dialog.scss: -------------------------------------------------------------------------------- 1 | // // Manually replacing this code 2 | .spectrum-Dialog { 3 | background: var(--spectrum-dialog-background-color, var(--spectrum-alias-background-color-default)); 4 | } 5 | .spectrum-Dialog { 6 | position: fixed; 7 | left: 50%; 8 | top: 50%; 9 | transform: translateX(-50%) translateY(-50%) translateY(var(--spectrum-dialog-entry-animation-distance, var(--spectrum-global-dimension-size-250))); 10 | z-index: 20; 11 | border-radius: var(--spectrum-dialog-border-radius, 4px); 12 | transition: 13 | opacity var(--spectrum-dialog-exit-animation-duration, var(--spectrum-global-animation-duration-100)) var(--spectrum-global-animation-ease-in, cubic-bezier(0.5, 0, 1, 1)) 0ms, 14 | visibility 0ms linear calc(0ms + var(--spectrum-dialog-exit-animation-duration, var(--spectrum-global-animation-duration-100))), 15 | transform 0ms linear calc(0ms + var(--spectrum-dialog-exit-animation-duration, var(--spectrum-global-animation-duration-100))); 16 | } 17 | .spectrum-Dialog { 18 | visibility: hidden; 19 | opacity: 0; 20 | transition: 21 | transform var(--spectrum-global-animation-duration-100, 130ms) ease-in-out, 22 | opacity var(--spectrum-global-animation-duration-100, 130ms) ease-in-out, 23 | visibility 0ms linear var(--spectrum-global-animation-duration-100, 130ms); 24 | pointer-events: none; 25 | } 26 | .spectrum-Dialog.is-open { 27 | transition: 28 | transform var(--spectrum-dialog-entry-animation-duration, var(--spectrum-global-animation-duration-500)) var(--spectrum-global-animation-ease-out, cubic-bezier(0, 0, 0.4, 1)) 29 | var(--spectrum-dialog-entry-animation-delay, var(--spectrum-global-animation-duration-200)), 30 | opacity var(--spectrum-dialog-entry-animation-duration, var(--spectrum-global-animation-duration-500)) var(--spectrum-global-animation-ease-out, cubic-bezier(0, 0, 0.4, 1)) 31 | var(--spectrum-dialog-entry-animation-delay, var(--spectrum-global-animation-duration-200)); 32 | transform: translate(-50%, calc(-50% + -2vh)); 33 | } 34 | 35 | .spectrum-Dialog.is-open { 36 | visibility: visible; 37 | opacity: 1; 38 | transition-delay: 0ms; 39 | pointer-events: auto; 40 | } 41 | 42 | #dialogOverlay { 43 | background-color: rgba(0, 0, 0, 0.4); 44 | position: fixed; 45 | display: none; 46 | top: 0; 47 | left: 0; 48 | height: 100vh; 49 | width: 100vw; 50 | z-index: 15; 51 | } 52 | -------------------------------------------------------------------------------- /docs/ui/src/scss/components/header.scss: -------------------------------------------------------------------------------- 1 | .spectrum-AppHeader { 2 | grid-area: header; 3 | display: flex; 4 | flex-direction: row; 5 | max-height: var(--spectrum-global-dimension-size-400); // 32px 6 | border-bottom: 2px solid var(--panelBorder); 7 | background-color: var(--headerBackground); 8 | margin: 0; 9 | padding: var(--spectrum-global-dimension-size-150) var(--spectrum-global-dimension-size-200); 10 | align-items: center; 11 | justify-content: space-between; 12 | 13 | .spectrum-ActionGroup { 14 | flex-shrink: 0; 15 | } 16 | .spectrum-Form--row { 17 | margin-right: 8px; 18 | } 19 | } 20 | 21 | .spectrum-AppHeader_item { 22 | display: flex; 23 | flex-direction: row; 24 | align-items: center; 25 | 26 | .spectrum-Tabs { 27 | height: 57px; 28 | margin-left: 48px; 29 | } 30 | } 31 | 32 | .spectrum-AppHeader_item--last { 33 | width: auto; 34 | justify-content: flex-end; 35 | 36 | @media screen and (min-width: 1160px) { 37 | width: 350px; 38 | } 39 | } 40 | 41 | .spectrum-AppHeader-Title { 42 | margin: 0; 43 | font-weight: 400; 44 | cursor: default; 45 | } 46 | 47 | #headerLogo { 48 | height: 24px; 49 | width: 24px; 50 | } 51 | #logoTitle { 52 | display: inline-flex; 53 | text-decoration: none; 54 | } 55 | #headerLogo ~ .spectrum-AppHeader-Title { 56 | margin-left: 8px; 57 | } 58 | #octo-link { 59 | margin-left: 16px; 60 | padding: 4px; 61 | } 62 | -------------------------------------------------------------------------------- /docs/ui/src/scss/components/highlightCode.scss: -------------------------------------------------------------------------------- 1 | /* Code syntax highlighting aliases */ 2 | .hljs-keyword { 3 | color: var(--spectrum-global-color-fuchsia-600); 4 | } 5 | .hljs-section { 6 | color: var(--spectrum-global-color-red-600); 7 | } 8 | .hljs-literal, 9 | .hljs-number { 10 | color: var(--spectrum-global-color-purple-600); 11 | } 12 | .hljs-attr { 13 | color: var(--spectrum-global-color-seafoam-600); 14 | } 15 | .hljs-title { 16 | color: var(--spectrum-global-color-indigo-600); 17 | } 18 | .hljs-title.class_ { 19 | color: var(--spectrum-global-color-blue-600); 20 | } 21 | .hljs-variable { 22 | color: var(--spectrum-global-color-magenta-600); 23 | } 24 | .hljs-string { 25 | color: var(--spectrum-global-color-fuchsia-600); 26 | } 27 | .hljs-function { 28 | color: var(--spectrum-global-color-blue-600); 29 | } 30 | .hljs-comment { 31 | color: var(--spectrum-global-color-gray-500); 32 | } 33 | -------------------------------------------------------------------------------- /docs/ui/src/scss/components/imageUploader.scss: -------------------------------------------------------------------------------- 1 | #image-preview { 2 | display: flex; 3 | flex-direction: row; 4 | align-items: center; 5 | 6 | img { 7 | object-fit: scale-down; 8 | height: 112px; 9 | margin-top: var(--spectrum-global-dimension-size-200); 10 | border-radius: var(--spectrum-alias-border-radius-regular); 11 | } 12 | 13 | .image-preview_text { 14 | margin-top: var(--spectrum-global-dimension-size-200); 15 | margin-left: var(--spectrum-global-dimension-size-100); 16 | size: var(--spectrum-global-dimension-font-size-50, 12px); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /docs/ui/src/scss/components/panelAccordion.scss: -------------------------------------------------------------------------------- 1 | .spectrum-Panel-Item--accordion { 2 | height: 16px; 3 | overflow: hidden; 4 | display: flex; 5 | flex-direction: column; 6 | transition: height ease-out 0.1s; 7 | 8 | .spectrum-Accordion-Header .spectrum-Icon { 9 | transform: rotate(-90deg); 10 | } 11 | 12 | &.is-open { 13 | height: auto; 14 | transition: height ease-out 0.1s; 15 | 16 | .spectrum-Accordion-Header .spectrum-Icon { 17 | transform: rotate(0deg); 18 | } 19 | } 20 | } 21 | 22 | .spectrum-Accordion-Header { 23 | position: relative; 24 | display: flex; 25 | flex-direction: row; 26 | cursor: pointer; 27 | } 28 | 29 | .spectrum-Accordion-Body .spectrum-Panel-Item { 30 | padding-left: 0; 31 | padding-right: 0; 32 | border-width: 1px; 33 | } 34 | 35 | .spectrum-Accordion-Body .spectrum-Panel-Item:first-of-type { 36 | padding-top: 0; 37 | } 38 | -------------------------------------------------------------------------------- /docs/ui/src/scss/components/popover.scss: -------------------------------------------------------------------------------- 1 | .spectrum-Popover--padded { 2 | padding: var(--spectrum-global-dimension-size-300); 3 | } 4 | 5 | .spectrum-Popover--paddedSmall { 6 | padding-left: var(--spectrum-global-dimension-size-100); 7 | padding-right: var(--spectrum-global-dimension-size-100); 8 | padding-bottom: var(--spectrum-global-dimension-size-200); 9 | } 10 | 11 | .spectrum-Popover { 12 | z-index: 100; 13 | 14 | .spectrum-Body { 15 | margin-top: 0.25rem; 16 | margin-bottom: 0.75rem; 17 | } 18 | } 19 | 20 | #popoverShareOptions { 21 | top: 50px; 22 | right: 72px; 23 | width: auto; 24 | .spectrum-ActionGroup--vertical { 25 | margin-top: var(--spectrum-global-dimension-size-100); 26 | margin-bottom: var(--spectrum-global-dimension-size-100); 27 | } 28 | } 29 | 30 | #popoverAdaptiveControls { 31 | top: 50px; 32 | right: 152px; 33 | width: 336px; 34 | } 35 | 36 | #popoverAnalysisColorSpace { 37 | top: 50px; 38 | right: 190px; 39 | width: 336px; 40 | } 41 | -------------------------------------------------------------------------------- /docs/ui/src/scss/components/sections.scss: -------------------------------------------------------------------------------- 1 | section { 2 | margin-top: 32px; 3 | } 4 | 5 | .section--centered { 6 | margin: 72px auto; 7 | text-align: center; 8 | } 9 | 10 | .section--split { 11 | display: grid; 12 | width: 100%; 13 | grid-template-rows: auto; 14 | grid-template-columns: 50% 50%; 15 | grid-column-gap: var(--spectrum-global-dimension-size-200); 16 | grid-template-areas: 'sectionLeft sectionRight'; 17 | } 18 | 19 | .section--left, 20 | .section--right { 21 | display: flex; 22 | flex-direction: column; 23 | justify-content: center; 24 | 25 | .spectrum-Body { 26 | max-width: 50ch; 27 | } 28 | } 29 | 30 | .section--left { 31 | grid-area: sectionLeft; 32 | } 33 | 34 | .section--right { 35 | grid-area: sectionRight; 36 | } 37 | 38 | .section--image { 39 | background-color: var(--spectrum-global-color-gray-200); 40 | height: 320px; 41 | width: auto; 42 | overflow: hidden; 43 | object-fit: cover; 44 | 45 | @media screen and (min-width: 1270px) { 46 | height: calc(70vh - 58px); 47 | min-height: 400px; 48 | max-height: 650px; 49 | } 50 | } 51 | 52 | #homeMainSection { 53 | margin-top: 0; 54 | width: 100%; 55 | } 56 | -------------------------------------------------------------------------------- /docs/ui/src/scss/components/selectBox.scss: -------------------------------------------------------------------------------- 1 | .selectBox--row { 2 | display: flex; 3 | flex-direction: row; 4 | flex-wrap: wrap; 5 | gap: var(--spectrum-global-dimension-size-200); 6 | width: 100%; 7 | } 8 | 9 | .selectBox { 10 | display: flex; 11 | flex-direction: column; 12 | align-items: center; 13 | justify-content: space-between; 14 | padding: var(--spectrum-global-dimension-size-400) var(--spectrum-global-dimension-size-300) var(--spectrum-global-dimension-size-300); 15 | border-radius: var(--spectrum-alias-border-radius-medium); 16 | border-width: 1px; 17 | border-style: solid; 18 | border-color: var(--spectrum-global-color-gray-300); 19 | background-color: var(--spectrum-global-color-gray-50); 20 | min-width: 180px; 21 | width: calc(33% - 58px); 22 | text-decoration: none; 23 | transition: 24 | border-color var(--spectrum-global-animation-duration-100, 130ms) ease-out, 25 | background-color var(--spectrum-global-animation-duration-100, 130ms) ease-out; 26 | 27 | &:hover { 28 | border-color: var(--spectrum-global-color-gray-400); 29 | background-color: var(--spectrum-global-color-gray-50); 30 | } 31 | &:active { 32 | border-color: var(--spectrum-global-color-gray-500); 33 | background-color: var(--spectrum-global-color-gray-50); 34 | } 35 | } 36 | 37 | .selectBox_Content { 38 | display: flex; 39 | flex-direction: column; 40 | align-items: center; 41 | } 42 | 43 | .selectBox_Button { 44 | margin-top: var(--spectrum-global-dimension-size-150); 45 | } 46 | 47 | .selectBox_image { 48 | width: 100px; 49 | height: 100px; 50 | } 51 | 52 | .spectrum-Body--sizeS.selectBox_content { 53 | margin-bottom: 0; 54 | text-align: center; 55 | line-height: 1.3; 56 | color: var(--spectrum-global-color-gray-700); 57 | } 58 | -------------------------------------------------------------------------------- /docs/ui/src/scss/components/statusLabel.scss: -------------------------------------------------------------------------------- 1 | .statusLabel { 2 | display: flex; 3 | flex-direction: row; 4 | height: 32px; 5 | grid-area: status; 6 | align-items: center; 7 | cursor: default; 8 | 9 | .statusLabel-text { 10 | margin-left: 4px; 11 | color: var(--spectrum-global-color-gray-700); 12 | } 13 | } 14 | 15 | .statusLabel--fail { 16 | .statusLabel-validationIcon { 17 | color: var(--spectrum-global-color-red-600); 18 | } 19 | .statusLabel-text { 20 | color: var(--spectrum-global-color-red-700); 21 | } 22 | } 23 | .statusLabel--pass { 24 | .statusLabel-validationIcon { 25 | color: var(--spectrum-global-color-green-600); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /docs/ui/src/scss/components/textfield.scss: -------------------------------------------------------------------------------- 1 | .spectrum-Textfield--custom { 2 | width: auto; 3 | 4 | .spectrum-Textfield-input { 5 | border-color: transparent; 6 | font-weight: var(--spectrum-heading-m-text-font-weight, var(--spectrum-alias-heading-text-font-weight-regular)); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /docs/ui/src/scss/components/toast.scss: -------------------------------------------------------------------------------- 1 | .spectrum-Toast { 2 | position: absolute; 3 | left: 50%; 4 | transform: translate(-50%, 100%); 5 | bottom: 0; 6 | display: none; 7 | 8 | &.is-visible { 9 | display: inline-flex; 10 | transform: translate(-50%, var(--toast-offset)); 11 | } 12 | 13 | &.hidden { 14 | display: none; 15 | } 16 | } 17 | 18 | .spectrum-Bounce { 19 | animation-duration: 250ms; 20 | animation-iteration-count: 1; 21 | animation-name: spectrum-Bounce; 22 | animation-timing-function: var(--spectrum-ease-in-out); 23 | } 24 | @keyframes spectrum-Bounce { 25 | 0% { 26 | transform: translate(-50%, 50%); 27 | opacity: 0; 28 | } 29 | 50% { 30 | transform: translate(-50%, var(--toast-offset-bounce-up-light)); 31 | opacity: 1; 32 | } 33 | 75% { 34 | transform: translate(-50%, var(--toast-offset)); 35 | opacity: 1; 36 | } 37 | 100% { 38 | transform: translate(-50%, var(--toast-offset)); 39 | opacity: 1; 40 | } 41 | } 42 | 43 | .spectrum-Exit { 44 | animation-duration: 220ms; 45 | animation-iteration-count: 1; 46 | animation-name: spectrum-Exit; 47 | animation-timing-function: var(--spectrum-ease-in-out); 48 | } 49 | @keyframes spectrum-Exit { 50 | 0% { 51 | transform: translate(-50%, var(--toast-offset)); 52 | opacity: 1; 53 | } 54 | 100% { 55 | transform: translate(-50%, 50%); 56 | opacity: 0; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /docs/ui/src/scss/components/tooltip.scss: -------------------------------------------------------------------------------- 1 | #BackgroundScaleTooltip { 2 | &.spectrum-Tooltip--top .spectrum-Tooltip-tip { 3 | right: 24px; 4 | left: auto; 5 | } 6 | &.spectrum-Tooltip--top { 7 | position: absolute; 8 | max-width: 30ch; 9 | } 10 | &.spectrum-Tooltip--top { 11 | transform: translate(94px, -48px); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /docs/ui/src/scss/converter.scss: -------------------------------------------------------------------------------- 1 | .appFrame { 2 | margin: 0; 3 | padding: 0; 4 | height: 100vh; 5 | overflow: hidden; 6 | font-family: 'Adobe Clean'; // local update since no typekit support currently. 7 | display: grid; 8 | grid-template-columns: auto; 9 | grid-template-rows: var(--header-height) auto; 10 | grid-column-gap: 0px; 11 | grid-row-gap: 0px; 12 | grid-template-areas: 13 | 'header' 14 | 'main'; 15 | } 16 | 17 | #output { 18 | font-family: 'Source Code Pro', monospace; 19 | margin-top: 16px; 20 | padding: 0 4px; 21 | color: #000000; 22 | font-size: 1rem; 23 | } 24 | 25 | #input { 26 | margin-right: 8px; 27 | } 28 | 29 | #converterWrapper { 30 | width: 100%; 31 | display: flex; 32 | flex-direction: column; 33 | align-items: center; 34 | overflow: auto; 35 | } 36 | 37 | #converterGroup { 38 | display: flex; 39 | flex-direction: column; 40 | align-items: flex-start; 41 | max-width: 100%; 42 | width: 860px; 43 | height: calc(100vh - 58px); 44 | max-height: 100%; 45 | justify-content: space-between; 46 | gap: 32px; 47 | } 48 | 49 | #converterGroup h1 { 50 | margin-top: 64px; 51 | } 52 | #converterGroup p { 53 | max-width: 60ch; 54 | } 55 | 56 | #converterGroup input[type='text'] + input[type='color'] { 57 | margin-left: 6px; 58 | } 59 | 60 | cite { 61 | color: #707070; 62 | } 63 | 64 | h1 + cite { 65 | margin-top: -4px; 66 | margin-bottom: 8px; 67 | } 68 | 69 | .spectrum-Form-item--row { 70 | display: flex; 71 | flex-direction: row; 72 | gap: 32px; 73 | 74 | // For some reason have to do this to retain proper width and keep from wrapping 75 | .spectrum-Form-item { 76 | width: 210px; 77 | } 78 | + .spectrum-Form-item--row { 79 | margin-top: var(--spectrum-global-dimension-size-400); 80 | } 81 | } 82 | 83 | .spectrum-Textfield { 84 | width: 21ch; 85 | } 86 | 87 | .converter--column { 88 | display: flex; 89 | flex-direction: column; 90 | gap: 8px; 91 | } 92 | .converter--row { 93 | display: flex; 94 | flex-direction: row; 95 | gap: 64px; 96 | justify-content: flex-start; 97 | } 98 | 99 | #demoWrapper { 100 | padding: 72px 48px; 101 | border-radius: 8px; 102 | border: 1px solid rgba(0, 0, 0, 0.15); 103 | height: 218px; 104 | display: flex; 105 | justify-content: center; 106 | 107 | #smallText { 108 | margin-top: 0.5rem; 109 | margin-bottom: 1rem; 110 | } 111 | } 112 | #largeText { 113 | font-size: 18.666px; 114 | font-weight: bold; 115 | } 116 | #smallText { 117 | font-size: 14px; 118 | } 119 | 120 | .contrastRatio { 121 | font-size: 64px; 122 | line-height: 1; 123 | color: #000; 124 | display: block; 125 | margin-bottom: 3rem; 126 | font-weight: 600; 127 | } 128 | 129 | #outputWrapper { 130 | h2 { 131 | margin-bottom: 0px; 132 | margin-top: 2rem; 133 | } 134 | } 135 | 136 | .badge { 137 | font-size: 14px; 138 | color: #ffffff; 139 | padding: 6px 8px; 140 | border-radius: 4px; 141 | display: inline-block; 142 | font-weight: 600; 143 | } 144 | 145 | .badge--error { 146 | background-color: #d60000; 147 | } 148 | .badge--success { 149 | background-color: #158000; 150 | } 151 | 152 | .passFail { 153 | display: inline-block; 154 | & + .passFail { 155 | margin-left: 24px; 156 | } 157 | } 158 | .heading--passFail { 159 | display: block; 160 | margin-bottom: 4px; 161 | } 162 | .ratioToOne { 163 | color: #6e6e6e; 164 | font-weight: 400; 165 | } 166 | 167 | #converterGroup .footer--cta { 168 | margin-bottom: 2em; 169 | margin-top: 4em; 170 | font-size: 14px; 171 | } 172 | 173 | // #contrastCheckInput { 174 | // height: 340px; 175 | // } 176 | 177 | #alphaSlider { 178 | width: 208px; 179 | } 180 | .spectrum-ColorSlider-slider { 181 | z-index: 1; 182 | pointer-events: all; 183 | -webkit-appearance: none; 184 | -moz-appearance: none; 185 | background: transparent; 186 | } 187 | -------------------------------------------------------------------------------- /docs/ui/src/theme.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 |
41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /docs/ui/src/tools.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 | 25 |
26 | 27 | 28 | 29 | 30 |
31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /docs/ui/src/views/GithubLink.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /docs/ui/src/views/LogoLink.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |

Leonardo

4 |
5 | -------------------------------------------------------------------------------- /docs/ui/src/views/dialog_bulkKeyColors.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

Add bulk key colors to color scale

4 |
5 |
6 | 7 |

Enter hex colors separated by comma or new line.

8 |

These will be added as key colors to this color scale.

9 |
10 |
11 |
12 | 13 |
14 | 15 |
16 |
17 |
18 |
19 |
20 | 21 | 22 | 23 |
24 |
25 |
26 | -------------------------------------------------------------------------------- /docs/ui/src/views/dialog_bulkLightnessStops.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

Import lightness stops

4 |
5 |
6 | 7 |

Enter hex colors separated by comma or new line.

8 |

These will be converted and added as lightness stops.

9 |
10 |
11 |
12 | 13 |
14 | 15 |
16 |
17 |
18 |
19 |
20 | 21 | 22 | 23 |
24 |
25 |
26 | -------------------------------------------------------------------------------- /docs/ui/src/views/dialog_importURL.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

Import from URL

4 |
5 |
6 | 7 |

Enter the URL of your existing color to add to this theme.

8 |

The configurations will be added to a new color scale.

9 |
10 |
11 |
12 | 13 |
14 | 15 |
16 |
17 |
18 |
19 | 23 |
24 | -------------------------------------------------------------------------------- /docs/ui/src/views/footer.html: -------------------------------------------------------------------------------- 1 | 9 | -------------------------------------------------------------------------------- /docs/ui/src/views/header.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 | 5 |
6 | 13 |
14 |
15 | 16 |
17 | 18 |
19 |
20 | -------------------------------------------------------------------------------- /docs/ui/src/views/header_scales.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 | 5 |
6 |
7 | 12 |
13 | 14 |
15 | 16 |
17 |
18 | 19 |
20 |
21 | 22 |
23 |
24 |
25 | 26 |
27 | 28 |
29 |
30 |
31 | 32 | 36 |
37 | 38 |
39 | 40 | 41 |
42 |
43 | 44 |
45 |
46 | -------------------------------------------------------------------------------- /docs/ui/src/views/header_tools.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 | 5 |
6 |
7 | 12 |
13 | 14 |
15 | 16 |
17 |
18 | 19 |
20 |
21 |
22 | 23 |
24 | 25 |
26 |
27 | -------------------------------------------------------------------------------- /docs/ui/src/views/home_articles.html: -------------------------------------------------------------------------------- 1 | 55 | -------------------------------------------------------------------------------- /docs/ui/src/views/home_contribute.html: -------------------------------------------------------------------------------- 1 |
2 |

Contribute

3 |
4 | 5 | 6 |
7 | -------------------------------------------------------------------------------- /docs/ui/src/views/home_learn.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

Learn Leonardo

4 |
5 | 6 |

Color

7 |

The color system tab is for defining your color palette and the color scales for each color.

8 |

9 | Your color palette represents each primary color of your system. You can evaluate the 10 | color harmony 11 | of your palette. The color wheel is available to view in a variety of 12 | color spaces . 13 |

14 |

Your color scales are a full value scale for each of your palette colors. This allows you to design color as a fluid continuum of tints and shades.

15 |

Color scales are defined by three parts: Color keys, interpolation colorspace, and smoothing.

16 | 17 |

Color keys

18 |

19 | Color keys are specific colors that you want the include within the scale. Each color key is automatically sorted and placed on the gradient by it's lightness. This is to ensure the scale follows a consistent change in lightness from dark to light 20 | colors. 21 |

22 | 23 |

Interpolation colorspace

24 |

25 | This specifies which color space you wish to interpolate between your color keys, black, and white. Color is defined differently within each color space, so the resulting gradient of your color scale will appear differently for each. 26 |

27 | 28 |

Smoothing

29 |

30 | Leonardo offers 31 | catmull-rom 32 | smoothing for all interpolation color spaces. By default, interpolation is linear. In some cases, this will yield good results. For other cases, smoothing provides an adjustment to the interpolation that makes the transition of colors within your 33 | color scale appear much more balanced and smooth. 34 |

35 |
36 |
37 | 53 |
54 | 55 | 56 |
57 | -------------------------------------------------------------------------------- /docs/ui/src/views/home_sidenav.html: -------------------------------------------------------------------------------- 1 | 14 | -------------------------------------------------------------------------------- /docs/ui/src/views/tab_colorConverter.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |
4 |
5 |

Convert color

6 | 7 |
8 |
9 | 10 |
11 | 12 |
13 |
14 | 15 |
16 |
17 |
18 |
19 | 20 |
21 |

Have a lot to convert?

22 |

Use the bulk converter to convert all your colors in the formats you need.

23 | 24 |
25 |
26 |
27 | 28 |
29 |
30 |
31 |
32 |
33 | 34 | 35 | 36 | 37 |
38 | -------------------------------------------------------------------------------- /docs/ui/src/views/tab_home.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 |
12 |
13 | -------------------------------------------------------------------------------- /docs/ui/src/views/toast_cvdPreview.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
You're in CVD simulation mode. Copying generated colors will not be affected by simulation mode.
4 | 7 |
8 |
9 | 14 |
15 |
16 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "leonardo-monorepo", 3 | "private": true, 4 | "author": "Nate Baldwin ", 5 | "scripts": { 6 | "moon": "moon", 7 | "pre-commit": "lint-staged", 8 | "prepare": "husky || true", 9 | "release": "changeset publish" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "git+https://github.com/adobe/leonardo.git" 14 | }, 15 | "contributors": ["Larry Davis ", "Frank Karstens ", "Garth Braithwaite (http://garthdb.com/)"], 16 | "license": "Apache-2.0", 17 | "devDependencies": { 18 | "@changesets/cli": "^2.27.1", 19 | "@commitlint/cli": "^19.3.0", 20 | "@commitlint/config-conventional": "^19.2.2", 21 | "@moonrepo/cli": "^1.24.5", 22 | "@parcel/packager-raw-url": "2.12.0", 23 | "@parcel/transformer-sass": "2.12.0", 24 | "@parcel/transformer-webmanifest": "2.12.0", 25 | "ava": "^6.1.3", 26 | "buffer": "^6.0.3", 27 | "husky": "^9.0.11", 28 | "lint-staged": "^15.2.2", 29 | "path-browserify": "^1.0.1", 30 | "prettier": "^3.2.5", 31 | "process": "^0.11.10", 32 | "vm-browserify": "^1.1.2" 33 | }, 34 | "packageManager": "pnpm@9.1.1", 35 | "engines": { 36 | "node": "~20.11" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /packages/contrast-colors/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "es6": true 5 | }, 6 | "extends": ["airbnb-base"], 7 | "parserOptions": { 8 | "ecmaVersion": 12 9 | }, 10 | "rules": { 11 | "max-len": "off", 12 | "no-param-reassign": "off", 13 | "no-plusplus": "off", 14 | "object-curly-newline": ["error", {"multiline": true}], 15 | "no-floating-decimal": "off", 16 | "prefer-destructuring": ["error", {"object": true, "array": false}], 17 | "consistent-return": "off", 18 | "no-underscore-dangle": "off", 19 | "no-console": "error", 20 | "camelcase": "off" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /packages/contrast-colors/.npmignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | test/ 3 | -------------------------------------------------------------------------------- /packages/contrast-colors/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2024 Adobe. All rights reserved. 3 | This file is licensed to you under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. You may obtain a copy 5 | of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | 7 | Unless required by applicable law or agreed to in writing, software distributed under 8 | the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS 9 | OF ANY KIND, either express or implied. See the License for the specific language 10 | governing permissions and limitations under the License. 11 | */ 12 | 13 | import chroma from 'chroma-js'; 14 | import {extendChroma} from './lib/chroma-plus.js'; 15 | import {convertColorValue, createScale, getContrast as contrast, luminance, minPositive, ratioName} from './lib/utils.js'; 16 | 17 | import {Color} from './lib/color.js'; 18 | import {BackgroundColor} from './lib/backgroundcolor.js'; 19 | import {Theme} from './lib/theme.js'; 20 | 21 | extendChroma(chroma); 22 | 23 | // console.color('#6fa7ff'); 24 | // console.ramp(chroma.scale(['yellow', 'navy']).mode('hsl')) 25 | 26 | export {Color, BackgroundColor, Theme, createScale, luminance, contrast, minPositive, ratioName, convertColorValue}; 27 | -------------------------------------------------------------------------------- /packages/contrast-colors/lib/backgroundcolor.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2024 Adobe. All rights reserved. 3 | This file is licensed to you under the Apache License, Version 2.0 (the 'License'); 4 | you may not use this file except in compliance with the License. You may obtain a copy 5 | of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software distributed under 7 | the License is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS 8 | OF ANY KIND, either express or implied. See the License for the specific language 9 | governing permissions and limitations under the License. 10 | */ 11 | 12 | import {hsluvArray, convertColorValue, createScale, removeDuplicates} from './utils.js'; 13 | 14 | import {Color} from './color.js'; 15 | 16 | class BackgroundColor extends Color { 17 | get backgroundColorScale() { 18 | if (!this._backgroundColorScale) { 19 | this._generateColorScale(); 20 | } 21 | return this._backgroundColorScale; 22 | } 23 | 24 | _generateColorScale() { 25 | // This would create a 100 color value array based on all parameters, 26 | // which can be used for sliding lightness as a background color 27 | 28 | // Call original generateColorScale method in the context of our background color 29 | // Then we can run the code for Color, but we've added in more below. 30 | Color.prototype._generateColorScale.call(this); 31 | 32 | // create massive scale 33 | const backgroundColorScale = createScale({ 34 | swatches: 1000, 35 | colorKeys: this._colorKeys, 36 | colorspace: this._colorspace, 37 | shift: 1, 38 | smooth: this._smooth 39 | }); 40 | 41 | // Inject original keycolors to ensure they are present in the background options 42 | backgroundColorScale.push(...this.colorKeys); 43 | 44 | const colorObj = backgroundColorScale 45 | // Convert to HSLuv and keep track of original indices 46 | .map((c, i) => ({value: Math.round(hsluvArray(c)[2]), index: i})); 47 | 48 | const colorObjFiltered = removeDuplicates(colorObj, 'value'); 49 | 50 | const bgColorArrayFiltered = colorObjFiltered.map((data) => backgroundColorScale[data.index]); 51 | 52 | // Manually cap the background array at 100 colors, then add white back to the end 53 | // since it sometimes gets removed. 54 | if (bgColorArrayFiltered.length >= 101) { 55 | bgColorArrayFiltered.length = 100; 56 | bgColorArrayFiltered.push('#ffffff'); 57 | } 58 | 59 | this._backgroundColorScale = bgColorArrayFiltered.map((color) => convertColorValue(color, this._output)); 60 | 61 | return this._backgroundColorScale; 62 | } 63 | } 64 | export {BackgroundColor}; 65 | -------------------------------------------------------------------------------- /packages/contrast-colors/moon.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Adobe. All rights reserved. 2 | # This file is licensed to you under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. You may obtain a copy 4 | # of the License at http://www.apache.org/licenses/LICENSE-2.0 5 | 6 | # Unless required by applicable law or agreed to in writing, software distributed under 7 | # the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS 8 | # OF ANY KIND, either express or implied. See the License for the specific language 9 | # governing permissions and limitations under the License. 10 | 11 | $schema: 'https://moonrepo.dev/schemas/project.json' 12 | type: library 13 | 14 | fileGroups: 15 | sources: 16 | - index.js 17 | - index.d.ts 18 | - 'lib/**/*' 19 | tests: 20 | - 'test/**/*' 21 | 22 | tasks: 23 | test: 24 | command: 25 | - ava 26 | inputs: 27 | - '@globs(tests)' 28 | - '@globs(sources)' 29 | platform: node 30 | test-watch: 31 | command: 32 | - ava 33 | - --watch 34 | local: true 35 | platform: node 36 | -------------------------------------------------------------------------------- /packages/contrast-colors/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@adobe/leonardo-contrast-colors", 3 | "version": "1.0.0", 4 | "description": "Generate colors based on a desired contrast ratio", 5 | "repository": "git@github.com:adobe/leonardo.git", 6 | "main": "./index.js", 7 | "type": "module", 8 | "types": "./index.d.ts", 9 | "exports": { 10 | ".": { 11 | "default": "./index.js" 12 | } 13 | }, 14 | "author": "Nate Baldwin ", 15 | "license": "Apache-2.0", 16 | "dependencies": { 17 | "apca-w3": "^0.1.9", 18 | "chroma-js": "^2.4.2", 19 | "ciebase": "^0.1.1", 20 | "ciecam02": "^0.4.6", 21 | "hsluv": "^0.1.0" 22 | }, 23 | "devDependencies": { 24 | "ava": "^6.1.1" 25 | }, 26 | "publishConfig": { 27 | "access": "public", 28 | "provenance": true 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /packages/contrast-colors/test/colorSetters.test.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2024 Adobe. All rights reserved. 3 | This file is licensed to you under the Apache License, Version 2.0 (the 'License'); 4 | you may not use this file except in compliance with the License. You may obtain a copy 5 | of the License at http://www.apache.org/licenses/LICENSE2.0 6 | Unless required by applicable law or agreed to in writing, software distributed under 7 | the License is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS 8 | OF ANY KIND, either express or implied. See the License for the specific language 9 | governing permissions and limitations under the License. 10 | */ 11 | 12 | import test from 'ava'; 13 | import {Color} from '../index.js'; 14 | 15 | test('should set color name of Color class', (t) => { 16 | const color = new Color({ 17 | name: 'colorName', 18 | colorKeys: ['#2451FF', '#C9FEFE', '#012676'], 19 | colorspace: 'CAM02', 20 | ratios: [3, 4.5], 21 | smooth: true 22 | }); 23 | 24 | color.name = 'newColorName'; 25 | const colorName = color.name; 26 | 27 | t.is(colorName, 'newColorName'); 28 | }); 29 | 30 | test('should set color keys of Color class', (t) => { 31 | const color = new Color({ 32 | name: 'colorName', 33 | colorKeys: ['#2451FF', '#C9FEFE', '#012676'], 34 | colorspace: 'CAM02', 35 | ratios: [3, 4.5], 36 | smooth: true 37 | }); 38 | 39 | color.colorKeys = ['#ff00ff', '#ff32ff', '#320077']; 40 | const colorKeys = color.colorKeys; 41 | 42 | t.deepEqual(colorKeys, ['#ff00ff', '#ff32ff', '#320077']); 43 | }); 44 | 45 | test('should set colorspace of Color class', (t) => { 46 | const color = new Color({ 47 | name: 'colorName', 48 | colorKeys: ['#2451FF', '#C9FEFE', '#012676'], 49 | colorspace: 'CAM02', 50 | ratios: [3, 4.5], 51 | smooth: true 52 | }); 53 | 54 | color.colorspace = 'HSL'; 55 | const colorspace = color.colorspace; 56 | t.is(colorspace, 'HSL'); 57 | }); 58 | 59 | test('should set ratios of Color class', (t) => { 60 | const color = new Color({ 61 | name: 'colorName', 62 | colorKeys: ['#2451FF', '#C9FEFE', '#012676'], 63 | colorspace: 'CAM02', 64 | ratios: [3, 4.5], 65 | smooth: true 66 | }); 67 | 68 | color.ratios = [5, 7, 12]; 69 | const ratios = color.ratios; 70 | t.deepEqual(ratios, [5, 7, 12]); 71 | }); 72 | 73 | test('should set smooth of Color class', (t) => { 74 | const color = new Color({ 75 | name: 'colorName', 76 | colorKeys: ['#2451FF', '#C9FEFE', '#012676'], 77 | colorspace: 'CAM02', 78 | ratios: [3, 4.5], 79 | smooth: true 80 | }); 81 | 82 | color.smooth = false; 83 | const smooth = color.smooth; 84 | 85 | t.false(smooth); 86 | }); 87 | -------------------------------------------------------------------------------- /packages/contrast-colors/test/createScale.test.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2024 Adobe. All rights reserved. 3 | This file is licensed to you under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. You may obtain a copy 5 | of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software distributed under 7 | the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS 8 | OF ANY KIND, either express or implied. See the License for the specific language 9 | governing permissions and limitations under the License. 10 | */ 11 | 12 | import test from 'ava'; 13 | import {createScale} from '../index.js'; 14 | 15 | test('should generate 8 colors in Lab', (t) => { 16 | const scale = createScale({ 17 | swatches: 8, 18 | colorKeys: ['#CCFFA9', '#FEFEC5', '#5F0198'], 19 | colorspace: 'LAB', 20 | shift: 1, 21 | fullScale: true 22 | }); 23 | t.deepEqual(scale, ['#ffffff', '#c6eba9', '#b6bda8', '#a48fa5', '#8e62a1', '#73329c', '#470d6e', '#000000']); 24 | }); 25 | 26 | test('should generate 8 colors in OKlab', (t) => { 27 | const scale = createScale({ 28 | swatches: 8, 29 | colorKeys: ['#CCFFA9', '#FEFEC5', '#5F0198'], 30 | colorspace: 'OKLAB', 31 | shift: 1, 32 | fullScale: true 33 | }); 34 | t.deepEqual(scale, ['#ffffff', '#c3ecac', '#adc0ae', '#9795ac', '#8169a7', '#6c399f', '#3d0064', '#000000']); 35 | }); 36 | 37 | test('should generate 8 colors in OKLCh', (t) => { 38 | const scale = createScale({ 39 | swatches: 8, 40 | colorKeys: ['#CCFFA9', '#FEFEC5', '#5F0198'], 41 | colorspace: 'OKLCH', 42 | shift: 1, 43 | fullScale: true 44 | }); 45 | t.deepEqual(scale, ['#ffffff', '#a1f5ac', '#00d8c0', '#00aed5', '#0079d9', '#503cbd', '#440077', '#000000']); 46 | }); 47 | -------------------------------------------------------------------------------- /packages/contrast-colors/test/minPositive.test.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2024 Adobe. All rights reserved. 3 | This file is licensed to you under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. You may obtain a copy 5 | of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software distributed under 7 | the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS 8 | OF ANY KIND, either express or implied. See the License for the specific language 9 | governing permissions and limitations under the License. 10 | */ 11 | 12 | import test from 'ava'; 13 | import {minPositive} from '../index.js'; 14 | 15 | test('should return 1', (t) => { 16 | const result = minPositive([1, 1.2, 1.4, 2, 3, 4.5, 6, 8, 12, 21]); 17 | t.is(result, 1); 18 | }); 19 | 20 | test('should return 2', (t) => { 21 | const result = minPositive([-3, -2, -1.2, 2, 3, 4.5, 6, 8, 12, 21]); 22 | t.is(result, 2); 23 | }); 24 | -------------------------------------------------------------------------------- /packages/contrast-colors/test/ratioName.test.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2024 Adobe. All rights reserved. 3 | This file is licensed to you under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. You may obtain a copy 5 | of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software distributed under 7 | the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS 8 | OF ANY KIND, either express or implied. See the License for the specific language 9 | governing permissions and limitations under the License. 10 | */ 11 | 12 | import test from 'ava'; 13 | import {ratioName} from '../index.js'; 14 | 15 | test('should output 10 numbers incremented by 100', (t) => { 16 | const theme = ratioName([1, 1.2, 1.4, 2, 3, 4.5, 6, 8, 12, 21]); 17 | t.deepEqual(theme, [100, 200, 300, 400, 500, 600, 700, 800, 900, 1000]); 18 | }); 19 | 20 | test('should output 10 numbers with first at 50', (t) => { 21 | const theme = ratioName([-1.5, 1.2, 1.4, 2, 3, 4.5, 6, 8, 12, 21]); 22 | t.deepEqual(theme, [50, 100, 200, 300, 400, 500, 600, 700, 800, 900]); 23 | }); 24 | -------------------------------------------------------------------------------- /packages/contrast-colors/test/searchColors.test.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2024 Adobe. All rights reserved. 3 | This file is licensed to you under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. You may obtain a copy 5 | of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software distributed under 7 | the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS 8 | OF ANY KIND, either express or implied. See the License for the specific language 9 | governing permissions and limitations under the License. 10 | */ 11 | 12 | import test from 'ava'; 13 | import {Color} from '../index.js'; 14 | import {searchColors, convertColorValue} from '../lib/utils.js'; 15 | 16 | test('should return blue color of 3.12:1 against white', (t) => { 17 | const color = new Color({ 18 | name: 'blue', 19 | colorKeys: ['#0000ff'], 20 | colorspace: 'LAB', 21 | ratios: [3.12] 22 | }); 23 | const bgRgbArray = [255, 255, 255]; 24 | const baseV = 100; 25 | const contrastColors = searchColors(color, bgRgbArray, baseV, color.ratios).map((clr) => convertColorValue(clr, 'RGB')); 26 | t.deepEqual(contrastColors, ['rgb(163, 121, 255)']); 27 | }); 28 | 29 | test('should return blue color of 3.12:1 against black', (t) => { 30 | const color = new Color({ 31 | name: 'blue', 32 | colorKeys: ['#0000ff'], 33 | colorspace: 'LAB', 34 | ratios: [3.12] 35 | }); 36 | const bgRgbArray = [0, 0, 0]; 37 | const baseV = 0; 38 | const contrastColors = searchColors(color, bgRgbArray, baseV, color.ratios).map((clr) => convertColorValue(clr, 'RGB')); 39 | t.deepEqual(contrastColors, ['rgb(80, 43, 255)']); // 3.13 40 | }); 41 | 42 | test('should return blue colors of 3:1 and 4.5:1 against white', (t) => { 43 | const color = new Color({ 44 | name: 'blue', 45 | colorKeys: ['#0000ff'], 46 | colorspace: 'LAB', 47 | ratios: [3, 4.5] 48 | }); 49 | const bgRgbArray = [255, 255, 255]; 50 | const baseV = 100; 51 | const contrastColors = searchColors(color, bgRgbArray, baseV, color.ratios).map((clr) => convertColorValue(clr, 'RGB')); 52 | t.deepEqual(contrastColors, ['rgb(167, 124, 255)', 'rgb(129, 84, 255)']); // 3.01 & 4.52 53 | }); 54 | 55 | test('should return blue colors of 3:1 and 4.5:1 against black', (t) => { 56 | const color = new Color({ 57 | name: 'blue', 58 | colorKeys: ['#0000ff'], 59 | colorspace: 'LAB', 60 | ratios: [3, 4.5] 61 | }); 62 | const bgRgbArray = [0, 0, 0]; 63 | const baseV = 0; 64 | const contrastColors = searchColors(color, bgRgbArray, baseV, color.ratios).map((clr) => convertColorValue(clr, 'RGB')); 65 | t.deepEqual(contrastColors, ['rgb(73, 38, 255)', 'rgb(126, 81, 255)']); // 3 & 4.51 66 | }); 67 | 68 | test('should return blue color of -1.3 against light gray', (t) => { 69 | const color = new Color({ 70 | name: 'blue', 71 | colorKeys: ['#0000ff'], 72 | colorspace: 'LAB', 73 | ratios: [-1.3] 74 | }); 75 | const bgRgbArray = [166, 166, 166]; 76 | const baseV = 65; 77 | const contrastColors = searchColors(color, bgRgbArray, baseV, color.ratios).map((clr) => convertColorValue(clr, 'RGB')); 78 | t.deepEqual(contrastColors, ['rgb(207, 176, 255)']); // 1.31 79 | }); 80 | 81 | test('should return blue color of -2 against dark gray', (t) => { 82 | const color = new Color({ 83 | name: 'blue', 84 | colorKeys: ['#0000ff'], 85 | colorspace: 'LAB', 86 | ratios: [-2] 87 | }); 88 | const bgRgbArray = [99, 99, 99]; 89 | const baseV = 40; 90 | const contrastColors = searchColors(color, bgRgbArray, baseV, color.ratios).map((clr) => convertColorValue(clr, 'RGB')); 91 | t.deepEqual(contrastColors, ['rgb(167, 125, 255)']); // 2.01 92 | }); 93 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - "packages/*" 3 | - "docs/*" 4 | --------------------------------------------------------------------------------