├── .github ├── CODEOWNERS ├── FUNDING.yml ├── workflows │ └── publish-vscode-extension.yml └── ISSUE_TEMPLATE │ └── tooltip-description-report.md ├── resources ├── swatches │ ├── generated │ │ └── .index │ └── swatch.svg ├── readme │ ├── copy.gif │ ├── preset.gif │ ├── favorite.gif │ ├── brightness.gif │ ├── logo-codeui.png │ ├── picker-dual.png │ ├── capton_falcom.jpg │ ├── codeui-hover.png │ ├── main-gradient.png │ └── demo-main-668-582.png ├── screenshots │ ├── picker.png │ ├── demo-main.png │ ├── viewtypes.png │ ├── preset-colors.png │ ├── targeting-mode.png │ ├── info-numbered-v2.png │ ├── demo-customization.png │ ├── demo-multi-feature.png │ ├── demo_codeui_views.png │ ├── customization-palette.png │ ├── animation_customizeColor.gif │ └── customization-standard.png ├── marketplace │ ├── codeui-128.png │ ├── codeui-300.png │ ├── logo-codeui.png │ └── logo-codeui-sm-300.png ├── light │ ├── brightness.svg │ ├── clear.svg │ ├── edit.svg │ └── view.svg ├── dark │ ├── brightness.svg │ ├── edit.svg │ ├── clear.svg │ └── view.svg └── activityBar │ ├── wireframe-swatch.svg │ ├── wireframe-swatch-thicc.svg │ └── activityBar.svg ├── .vscode ├── .ropeproject │ ├── objectdb │ └── config.py ├── extensions.json ├── settings.json ├── tasks.json └── launch.json ├── CODING_GUIDELINES.md ├── .prettierrc ├── tsconfig.json ├── .gitignore ├── .vscodeignore ├── src ├── utils │ └── cache.ts ├── statusbar.ts ├── configuration.ts ├── theme.ts ├── color.ts ├── extension.ts ├── info.ts └── elements.ts ├── .eslintrc.js ├── LICENSE.md ├── data ├── colors-license.md └── defaultColors_dark.json ├── media ├── lib │ ├── reinvented-color-wheel.css │ └── reinvented-color-wheel.min.js └── main.js ├── CONTRIBUTING.md ├── CHANGELOG.md ├── README.md ├── gulpfile.js ├── package.json └── USAGE.md /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @ryanraposo -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: ryanraposo 2 | -------------------------------------------------------------------------------- /resources/swatches/generated/.index: -------------------------------------------------------------------------------- 1 | index -------------------------------------------------------------------------------- /resources/readme/copy.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ryanraposo/codeui/HEAD/resources/readme/copy.gif -------------------------------------------------------------------------------- /resources/readme/preset.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ryanraposo/codeui/HEAD/resources/readme/preset.gif -------------------------------------------------------------------------------- /.vscode/.ropeproject/objectdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ryanraposo/codeui/HEAD/.vscode/.ropeproject/objectdb -------------------------------------------------------------------------------- /resources/readme/favorite.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ryanraposo/codeui/HEAD/resources/readme/favorite.gif -------------------------------------------------------------------------------- /resources/readme/brightness.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ryanraposo/codeui/HEAD/resources/readme/brightness.gif -------------------------------------------------------------------------------- /resources/readme/logo-codeui.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ryanraposo/codeui/HEAD/resources/readme/logo-codeui.png -------------------------------------------------------------------------------- /resources/readme/picker-dual.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ryanraposo/codeui/HEAD/resources/readme/picker-dual.png -------------------------------------------------------------------------------- /resources/screenshots/picker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ryanraposo/codeui/HEAD/resources/screenshots/picker.png -------------------------------------------------------------------------------- /resources/readme/capton_falcom.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ryanraposo/codeui/HEAD/resources/readme/capton_falcom.jpg -------------------------------------------------------------------------------- /resources/readme/codeui-hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ryanraposo/codeui/HEAD/resources/readme/codeui-hover.png -------------------------------------------------------------------------------- /resources/readme/main-gradient.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ryanraposo/codeui/HEAD/resources/readme/main-gradient.png -------------------------------------------------------------------------------- /resources/screenshots/demo-main.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ryanraposo/codeui/HEAD/resources/screenshots/demo-main.png -------------------------------------------------------------------------------- /resources/screenshots/viewtypes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ryanraposo/codeui/HEAD/resources/screenshots/viewtypes.png -------------------------------------------------------------------------------- /resources/marketplace/codeui-128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ryanraposo/codeui/HEAD/resources/marketplace/codeui-128.png -------------------------------------------------------------------------------- /resources/marketplace/codeui-300.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ryanraposo/codeui/HEAD/resources/marketplace/codeui-300.png -------------------------------------------------------------------------------- /resources/marketplace/logo-codeui.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ryanraposo/codeui/HEAD/resources/marketplace/logo-codeui.png -------------------------------------------------------------------------------- /CODING_GUIDELINES.md: -------------------------------------------------------------------------------- 1 | # Coding Guidelines 2 | 3 | - show me your moves 4 | 5 | ![the cap](./resources/readme/capton_falcom.jpg) 6 | -------------------------------------------------------------------------------- /resources/readme/demo-main-668-582.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ryanraposo/codeui/HEAD/resources/readme/demo-main-668-582.png -------------------------------------------------------------------------------- /resources/screenshots/preset-colors.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ryanraposo/codeui/HEAD/resources/screenshots/preset-colors.png -------------------------------------------------------------------------------- /resources/screenshots/targeting-mode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ryanraposo/codeui/HEAD/resources/screenshots/targeting-mode.png -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "useTabs": true, 3 | "tabWidth": 4, 4 | "singleQuote": true, 5 | "printWidth": 100, 6 | "semi": true 7 | } 8 | -------------------------------------------------------------------------------- /resources/screenshots/info-numbered-v2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ryanraposo/codeui/HEAD/resources/screenshots/info-numbered-v2.png -------------------------------------------------------------------------------- /resources/marketplace/logo-codeui-sm-300.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ryanraposo/codeui/HEAD/resources/marketplace/logo-codeui-sm-300.png -------------------------------------------------------------------------------- /resources/screenshots/demo-customization.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ryanraposo/codeui/HEAD/resources/screenshots/demo-customization.png -------------------------------------------------------------------------------- /resources/screenshots/demo-multi-feature.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ryanraposo/codeui/HEAD/resources/screenshots/demo-multi-feature.png -------------------------------------------------------------------------------- /resources/screenshots/demo_codeui_views.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ryanraposo/codeui/HEAD/resources/screenshots/demo_codeui_views.png -------------------------------------------------------------------------------- /resources/screenshots/customization-palette.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ryanraposo/codeui/HEAD/resources/screenshots/customization-palette.png -------------------------------------------------------------------------------- /resources/screenshots/animation_customizeColor.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ryanraposo/codeui/HEAD/resources/screenshots/animation_customizeColor.gif -------------------------------------------------------------------------------- /resources/screenshots/customization-standard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ryanraposo/codeui/HEAD/resources/screenshots/customization-standard.png -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // See http://go.microsoft.com/fwlink/?LinkId=827846 3 | // for the documentation about the extensions.json format 4 | "recommendations": [ 5 | "dbaeumer.vscode-eslint" 6 | ] 7 | } -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es6", 5 | "lib": ["es6"], 6 | "outDir": "out", 7 | "sourceMap": true, 8 | "strict": true, 9 | "rootDir": "src" 10 | }, 11 | "exclude": ["node_modules", ".vscode-test"] 12 | } 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | #Folders 2 | external 3 | out 4 | node_modules 5 | resources/master 6 | local 7 | 8 | #Files 9 | todo.md 10 | dc.bat 11 | .vscodeignore 12 | CONTRIBUTING-template.md 13 | resources/swatches/generated/*.svg 14 | 15 | #Filetypes 16 | *.vsix 17 | .vscode/** 18 | 19 | 20 | -------------------------------------------------------------------------------- /.vscodeignore: -------------------------------------------------------------------------------- 1 | # Folders 2 | external 3 | resources/master 4 | 5 | # Files 6 | CODING_GUIDELINES.md 7 | CONTRIBUTING-template.md 8 | CONTRIBUTING.md 9 | todo.md 10 | dc.bat 11 | .prettierrc 12 | .eslintrc.js 13 | 14 | #Default 15 | .vscode/** 16 | .vscode-test/** 17 | out/test/** 18 | src/** 19 | .gitignore 20 | vsc-extension-quickstart.md 21 | **/tsconfig.json 22 | **/tslint.json 23 | **/*.map 24 | **/*.ts 25 | 26 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | // Place your settings in this file to overwrite default and user settings. 2 | { 3 | "files.exclude": { 4 | "out": false // set this to true to hide the "out" folder with the compiled JS files 5 | }, 6 | "search.exclude": { 7 | "out": true // set this to false to include "out" folder in search results 8 | }, 9 | // Turn off tsc task auto detection since we have the necessary tasks as npm scripts 10 | "typescript.tsc.autoDetect": "off", 11 | } -------------------------------------------------------------------------------- /src/utils/cache.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | import * as fs from 'fs'; 3 | import * as path from 'path'; 4 | 5 | /** 6 | * Deletes files generated by the extension. 7 | */ 8 | export function clearCache(filename : string) { 9 | const cache = path.join(filename, '..', '..', 'resources', 'swatches', 'generated'); 10 | fs.readdir(cache, (err, files) => { 11 | if (err) throw err; 12 | for (const file of files) { 13 | if (file !== '.index') { 14 | fs.unlink(path.join(cache, file), (err) => { 15 | if (err) throw err; 16 | }); 17 | } 18 | } 19 | }); 20 | } -------------------------------------------------------------------------------- /.github/workflows/publish-vscode-extension.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | tags: 4 | - "*" 5 | 6 | name: Deploy Extension 7 | jobs: 8 | deploy: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v2 12 | - uses: actions/setup-node@v1 13 | with: 14 | node-version: 12 15 | - run: npm ci 16 | - name: Visual Studio Marketplace 17 | uses: HaaLeo/publish-vscode-extension@v0 18 | with: 19 | pat: ${{ secrets.VS_MARKETPLACE_TOKEN }} 20 | registryUrl: https://marketplace.visualstudio.com -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | // See https://go.microsoft.com/fwlink/?LinkId=733558 2 | // for the documentation about the tasks.json format 3 | { 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "type": "npm", 8 | "script": "watch", 9 | "problemMatcher": "$tsc-watch", 10 | "isBackground": true, 11 | "presentation": { 12 | "reveal": "never" 13 | }, 14 | "group": { 15 | "kind": "build", 16 | "isDefault": true 17 | } 18 | }, 19 | { 20 | "type": "npm", 21 | "script": "lint", 22 | "problemMatcher": ["$eslint-stylish"], 23 | "label": "npm: lint", 24 | "detail": "eslint -c .eslintrc.js --ext .ts src" 25 | } 26 | ] 27 | } 28 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | /**@type {import('eslint').Linter.Config} */ 2 | // eslint-disable-next-line no-undef 3 | module.exports = { 4 | root: true, 5 | env : { 6 | "browser":true, 7 | "node": true, 8 | "commonjs": true, 9 | "es6": true 10 | }, 11 | parser: '@typescript-eslint/parser', 12 | plugins: ['@typescript-eslint'], 13 | extends: [ 14 | 'eslint:recommended', 15 | 'plugin:@typescript-eslint/recommended', 16 | 'prettier', 17 | 'prettier/@typescript-eslint', 18 | ], 19 | rules: { 20 | semi: [2, 'always'], 21 | '@typescript-eslint/no-unused-vars': 0, 22 | '@typescript-eslint/no-explicit-any': 0, 23 | '@typescript-eslint/explicit-module-boundary-types': 0, 24 | '@typescript-eslint/no-non-null-assertion': 0, 25 | }, 26 | }; 27 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/tooltip-description-report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Tooltip Description report 3 | about: Report an incomplete, incorrect, or missing element description 4 | title: "[TOOLTIP DESCRIPTION]" 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Identify the item** 11 | Describe the tree item lacking an appropriate description. 12 | 13 | **Expected (optional)** 14 | Provide a description of your own for consideration. 15 | 16 | **Screenshot (optional)** 17 | If applicable, add a screenshot. Screen-shotting tooltips can be problematic on some systems. 18 | 19 | **Additional context** 20 | Navigate to user-settings and begin adding the element to 'workbench.colorCustomizations'. A tooltip should display. If there is a discrepancy, please indicate that here. 21 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Ryan Raposo 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | // A launch configuration that compiles the extension and then opens it inside a new window 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | { 6 | "version": "0.2.0", 7 | "configurations": [ 8 | { 9 | "name": "Debug Extension", 10 | "type": "extensionHost", 11 | "request": "launch", 12 | "runtimeExecutable": "${execPath}", 13 | "args": [ 14 | "--extensionDevelopmentPath=${workspaceFolder}" 15 | ], 16 | "outFiles": [ 17 | "${workspaceFolder}/out/**/*.js" 18 | ], 19 | "preLaunchTask": "npm: watch" 20 | }, 21 | { 22 | "name": "Extension Tests", 23 | "type": "extensionHost", 24 | "request": "launch", 25 | "runtimeExecutable": "${execPath}", 26 | "args": [ 27 | "--disable-extensions", 28 | "--extensionDevelopmentPath=${workspaceFolder}", 29 | "--extensionTestsPath=${workspaceFolder}/out/test", 30 | ], 31 | "outFiles": [ 32 | "${workspaceFolder}/out/test/**/*.js" 33 | ], 34 | "preLaunchTask": "npm: watch" 35 | } 36 | ] 37 | } -------------------------------------------------------------------------------- /data/colors-license.md: -------------------------------------------------------------------------------- 1 | Refers to 'colors.json' 2 | 3 | MIT License 4 | 5 | Copyright (c) 2017 Alexander Cheprasov 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | SOFTWARE. -------------------------------------------------------------------------------- /media/lib/reinvented-color-wheel.css: -------------------------------------------------------------------------------- 1 | .reinvented-color-wheel, .reinvented-color-wheel--hue-handle, .reinvented-color-wheel--hue-wheel, .reinvented-color-wheel--sv-handle, .reinvented-color-wheel--sv-space { 2 | touch-action: manipulation; 3 | touch-action: none; 4 | -webkit-touch-callout: none; 5 | -webkit-tap-highlight-color: transparent; 6 | -webkit-user-select: none; 7 | -moz-user-select: none; 8 | -ms-user-select: none; 9 | user-select: none 10 | } 11 | 12 | .reinvented-color-wheel { 13 | position: fixed; 14 | display: inline-block; 15 | line-height: 0; 16 | border-radius: 50%; 17 | top:50%; 18 | left: 50%; 19 | transform: translate(-50%,-50%); 20 | } 21 | 22 | .reinvented-color-wheel--hue-wheel { 23 | border-radius: 50% 24 | } 25 | 26 | .reinvented-color-wheel--sv-space { 27 | position: absolute; 28 | left: 0; 29 | top: 0; 30 | right: 0; 31 | bottom: 0; 32 | margin: auto 33 | } 34 | 35 | .reinvented-color-wheel--hue-handle, .reinvented-color-wheel--sv-handle { 36 | position: absolute; 37 | box-sizing: border-box; 38 | border-radius: 50%; 39 | border: 2px solid #fff; 40 | box-shadow: 0 0 0 1px #000 inset 41 | } 42 | 43 | .reinvented-color-wheel--hue-handle { 44 | pointer-events: none 45 | } -------------------------------------------------------------------------------- /media/main.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-undef */ 2 | /* eslint-disable @typescript-eslint/ban-ts-comment */ 3 | // @ts-nocheck 4 | 5 | (function () { 6 | const vscode = acquireVsCodeApi(); 7 | 8 | const initialColor = '#3fdaa4'; 9 | 10 | document.addEventListener('contextmenu', function(ev) { 11 | ev.preventDefault(); 12 | }, false); 13 | 14 | var currentState = vscode.getState() || { color: initialColor }; 15 | 16 | function updateSelectedColor(color) { 17 | vscode.postMessage({ type: 'updateSelectedColor', value: color }); 18 | } 19 | 20 | function saveState(state) { 21 | vscode.setState({ color: state.color }); 22 | currentState = state; 23 | updateSelectedColor(state.color); 24 | } 25 | 26 | window.addEventListener('message', (event) => { 27 | const message = event.data; 28 | switch (message.type) { 29 | case 'setSelectedColor': { 30 | colorWheel.hex = message.value; 31 | break; 32 | } 33 | } 34 | }); 35 | 36 | var colorWheel = new ReinventedColorWheel({ 37 | appendTo: document.getElementById('color-wheel-container'), 38 | hex: currentState.selectedColor, 39 | wheelDiameter: 200, 40 | wheelThickness: 20, 41 | handleDiameter: 16, 42 | wheelReflectsSaturation: true, 43 | 44 | onChange: function (color) { 45 | saveState({ color: color.hex }); 46 | }, 47 | }); 48 | saveState({ color: colorWheel.hex }); 49 | })(); 50 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # LoveIt;ShipIt 2 | 3 | [![LoveIt;ShipIt](https://gitlab.com/ryanraposo/LoveItShipIt/-/raw/master/sticker/loveitshipit.svg)](http://github.com/ryanraposo/LoveItShipIt) 4 | 5 | Below is a reaffirmation from the maintainers of this project to our contributor counterparts. 6 | 7 | [LoveIt;ShipIt](https://github.com/ryanraposo/LoveItShipIt) is... 8 | 9 | 1. The order of operations in the project, and so better stands to be. 10 | 2. The standard for all changes, and so better stands to be. 11 | 3. The ideal communication between members of the project, above all else. 12 | 13 | The maintainer(s) of CodeUI have reaffirmed with honest belief... 14 | 15 | 1. That these reaffirmations preserve the true value of the project. 16 | 2. That contributors can expect the highest possible degree of respect as a result. 17 | 3. That doing so is the surest way to invoke the sentiment from users. 18 | 19 | # Contributing 20 | 21 | You don't need to create Issues first, or contact the owner (@ryanraposo), but both are HIGHLY welcome/encouraged for contributions or ideas that are unusual, unsupported, or generally underrepresented on GitHub. 22 | 23 | Feel welcome to contribute--whatever the word means to you. :) 24 | 25 | ``` 26 | I think it's time to give me all your praises 27 | So I can get this money and give all the homies raises 28 | My life is on these words, this is my affidavit 29 | 30 | -Larry Fish 31 | ``` 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /src/statusbar.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | 3 | /** 4 | * A command status bar item. Displays and toggles contributed setting 'codeui.targetingMode'. 5 | */ 6 | export class TargetingModeStatusBarItem { 7 | private instance: vscode.StatusBarItem; 8 | 9 | constructor() { 10 | this.instance = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right); 11 | this.instance.tooltip = 'Targeting mode for customizations applied by CodeUI.'; 12 | this.instance.command = 'toggleTargetingMode'; 13 | this.instance.text = '[CodeUI]:'; 14 | this.instance.show(); 15 | } 16 | /** 17 | * Updates the text content of the status bar item. 18 | * 19 | */ 20 | update(targetingMode: string | undefined) { 21 | this.instance.text = 22 | targetingMode === 'themeSpecific' ? '[CodeUI]: Theme-specific' : '[CodeUI]: General'; 23 | } 24 | } 25 | 26 | /** 27 | * A command status bar item. Displays hex and hue of selected color from the 'Color' view. 28 | * Copies to clipboard on click. 29 | */ 30 | export class ColorStatusBarItem { 31 | private instance: vscode.StatusBarItem; 32 | constructor() { 33 | this.instance = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left); 34 | this.instance.text = ''; 35 | this.instance.command = 'copySelectedColor'; 36 | this.instance.show(); 37 | } 38 | /** 39 | * Updates the text content & color of the status bar item. 40 | * 41 | */ 42 | update(color: string) { 43 | this.instance.text = color; 44 | this.instance.color = color; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## [1.1.0] 2 | 3 | - Centered the color picker (@devXprite) 4 | 5 | ## [1.0.1] 6 | 7 | - Update license 8 | 9 | ## [1.0.0] 10 | 11 | - Added Color Picker 12 | 13 | ## [0.3.3] 14 | 15 | - Fixed issue where customizations would only apply if there was an existing entry for "workbench.colorCustomizations" in settings. 16 | 17 | ## [0.3.2] 18 | 19 | - Fixed elements not showing full names in Palette view. 20 | 21 | ## [0.3.1] 22 | 23 | - Fixed various low-level performance issues. 24 | 25 | - Fixed outdated links in README. 26 | 27 | ## [0.3.0] 28 | 29 | - Added support for custom-value brightness adjustments (@usernamehw). 30 | 31 | - Added support for built-in color picker when editing 'codeui.favoriteColors' in settings. (@usernamehw) 32 | 33 | - Added configuration 'codeui.preferredScope'. Controls scoping behaviour when a workspace/folder is open. 34 | 35 | - Changed startup behaviour. CodeUI will now activate when accessed, not when VS Code is launched. (@usernamehw) 36 | 37 | - Changed extension description. 38 | 39 | - Fixed several element listings with unexpected names. 40 | 41 | ## [0.2.0] 42 | 43 | - Added Targeting Mode. Allows toggling between 'themeSpecific' and 'general' contexts for all customization commands. 44 | 45 | ## [0.1.2] 46 | 47 | - Changed release notes schema (readme.md) 48 | 49 | - Fixed duplicate section (usage.md) 50 | 51 | ## [0.1.1] 52 | 53 | - Fixed light-theme icon contrast for treeview command buttons 54 | 55 | ## [0.1.0] 56 | 57 | - View & customize the colors of VS Code's interface 58 | 59 | - Global workbench customization only 60 | -------------------------------------------------------------------------------- /src/configuration.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | import * as vscode from 'vscode'; 3 | 4 | class Config { 5 | private config: vscode.WorkspaceConfiguration; 6 | 7 | constructor() { 8 | this.config = vscode.workspace.getConfiguration(); 9 | } 10 | 11 | getColorThemeName() { 12 | return this.config.get('workbench.colorTheme'); 13 | } 14 | 15 | getWorkbenchColorCustomizations(scope: vscode.ConfigurationTarget) { 16 | const customizationSettingsObj = this.config.inspect('workbench.colorCustomizations'); 17 | let workbenchColorCustomizations : any = {}; 18 | 19 | if (customizationSettingsObj) { 20 | if (scope === vscode.ConfigurationTarget.Global) { 21 | workbenchColorCustomizations = customizationSettingsObj.globalValue; 22 | } 23 | if (scope === vscode.ConfigurationTarget.Workspace) { 24 | workbenchColorCustomizations = customizationSettingsObj.workspaceValue; 25 | } 26 | } 27 | if (workbenchColorCustomizations === undefined) { 28 | return {}; 29 | } 30 | return workbenchColorCustomizations; 31 | } 32 | 33 | getWorkspaceRootFolder(): vscode.WorkspaceFolder | undefined { 34 | if (vscode.workspace.workspaceFolders) { 35 | return vscode.workspace.workspaceFolders[0] || undefined; 36 | } 37 | } 38 | 39 | getTargetingMode(): string | undefined { 40 | return this.config.get('codeui.targetingMode'); 41 | } 42 | 43 | toggleTargetingMode() { 44 | this.config = vscode.workspace.getConfiguration(); 45 | const targetingMode = this.getTargetingMode(); 46 | this.config.update( 47 | 'codeui.targetingMode', 48 | targetingMode == 'general' ? 'themeSpecific' : 'general', 49 | vscode.ConfigurationTarget.Global 50 | ); 51 | } 52 | 53 | getPreferredScope() { 54 | return this.config.get('codeui.preferredScope', 'alwaysAsk'); 55 | } 56 | } 57 | 58 | export function getConfig() { 59 | return new Config(); 60 | } 61 | -------------------------------------------------------------------------------- /src/theme.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | import * as path from 'path'; 3 | import * as fs from 'fs'; 4 | import * as jsonc from 'jsonc-parser'; 5 | 6 | import { getConfig } from './configuration'; 7 | 8 | export function getCurrentColorTheme(): ColorTheme { 9 | const config = getConfig(); 10 | const themeName = config.getColorThemeName(); 11 | return new ColorTheme(themeName); 12 | } 13 | 14 | export class ColorTheme { 15 | private themePath: any; 16 | private themeObject: any; 17 | name: string; 18 | 19 | constructor(colorThemeName: string) { 20 | this.name = colorThemeName; 21 | this.themePath = this.getThemePath(colorThemeName); 22 | this.themeObject = this.getThemeObject(this.themePath); 23 | } 24 | 25 | private getThemePath(userSettingsTheme: any): any { 26 | try { 27 | for (const extension of vscode.extensions.all) { 28 | const contributions: any = extension.packageJSON['contributes']; 29 | if (contributions) { 30 | if (contributions['themes']) { 31 | for (const theme of contributions['themes']) { 32 | if (theme['label'] === userSettingsTheme) { 33 | return path.join(extension.extensionPath, theme['path']); 34 | } 35 | } 36 | } 37 | } 38 | } 39 | } catch { 40 | return undefined; 41 | } 42 | } 43 | 44 | private getThemeObject(themePath: any): any { 45 | let text = ''; 46 | if (themePath) { 47 | text = fs.readFileSync(themePath, 'utf8'); 48 | const jsonObject = jsonc.parse(text); 49 | return jsonObject; 50 | } 51 | } 52 | 53 | get workbenchColorCustomizations(): any { 54 | if (!this.themeObject) { 55 | return undefined; 56 | } 57 | const workbenchCustomizations = this.themeObject.colors; 58 | return workbenchCustomizations; 59 | } 60 | 61 | get type() { 62 | try { 63 | return this.themeObject['type']; 64 | } catch { 65 | return '-'; 66 | } 67 | } 68 | 69 | get author() { 70 | try { 71 | return this.themeObject['author']; 72 | } catch { 73 | return '-'; 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /resources/swatches/swatch.svg: -------------------------------------------------------------------------------- 1 | 2 | 13 | 15 | 17 | 18 | 20 | image/svg+xml 21 | 23 | 24 | 25 | 26 | 27 | 29 | 33 | 34 | 35 | 36 | 38 | 41 | 45 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 | CodeUI 5 |
6 |
7 |
8 | 9 | Customize your color theme for VS Code. 10 | 11 | [![LoveIt;ShipIt](https://gitlab.com/ryanraposo/LoveItShipIt/-/raw/master/sticker/loveitshipit.svg)](http://github.com/ryanraposo/LoveItShipIt) 12 | 13 | ![Visual Studio Marketplace Version](https://img.shields.io/visual-studio-marketplace/v/ryanraposo.codeui) 14 | ![Visual Studio Marketplace Installs](https://img.shields.io/visual-studio-marketplace/i/ryanraposo.codeui) 15 | ![GitHub License](https://img.shields.io/badge/license-MIT-blue.svg) 16 | 17 |
18 | 19 | # Table of Contents 20 | 21 | - [Table of Contents](#table-of-contents) 22 | - [Features](#features) 23 | - [Interface](#interface) 24 | - [Colors](#colors) 25 | - [Customization](#customization) 26 | - [Installing](#installing) 27 | - [Usage](#usage) 28 | - [Get Involved](#get-involved) 29 | 30 | # Features 31 | 32 | ## Interface 33 | 34 | Browse the elements of VS Code's interface and adjust your color settings in realtime. 35 | 36 | ![Screenshot](./resources/readme/picker-dual.png) 37 | 38 | ## Colors 39 | 40 | Use the built-in color picker, enter custom values, or choose from over 2k preset colors. Store your favorites via ```codeui.favoriteColors```. 41 | 42 | ## Customization 43 | 44 | Customize colors by theme and workspace. Darken, lighten, copy & paste values across items. Use Standard or Palette view to sort by element groups, or target specific colors wherever they appear. 45 | 46 | *Note: by default, customizations are applied to all workspaces and target the current theme.* 47 | 48 | # Installing 49 | 50 | The recommended method for installing CodeUI is via the Extension Marketplace, accessed from within Visual Studio Code. 51 | 52 | Alternatively, you can download the VSIX from [releases](https://github.com/ryanraposo/codeui/releases) and install using the terminal with command: 53 | 54 | ``` 55 | code --install-extension codeui-1.1.0.vsix 56 | ``` 57 | 58 | *Note: it may be necessary to reload vscode if installing via the terminal.* 59 | 60 | # Usage 61 | 62 | Refer to usage documentation [here. ](./USAGE.md) 63 | 64 | # Get Involved 65 | 66 | Help make CodeUI the standard theming tool for vscode! Whether it's new features, optimizations, documentation or bug reports - we appreciate your help. You can join the project on [Github](https://github.com/ryanraposo/codeui). 67 | 68 | Customizing the UI is a huge part of vscode's charm. Your feedback and contributions will make it as fun & accessible as possible. 69 | 70 | Thank you for supporting CodeUI! 71 | -------------------------------------------------------------------------------- /resources/light/brightness.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 21 | 41 | 43 | 44 | 46 | image/svg+xml 47 | 49 | 50 | 51 | 52 | 53 | 58 | 64 | 65 | 69 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /resources/dark/brightness.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 21 | 41 | 43 | 44 | 46 | image/svg+xml 47 | 49 | 50 | 51 | 52 | 53 | 58 | 64 | 65 | 69 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-var-requires */ 2 | const fs = require('fs'); 3 | const inquirer = require('inquirer'); 4 | 5 | 6 | function updateReadme(newVersion) { 7 | const re = /(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)/gm; 8 | 9 | let readme = fs.readFileSync('./README.md', {encoding:'utf8', flag:'r'}); 10 | 11 | readme = readme.replaceAll(re, newVersion); 12 | 13 | fs.writeFileSync('./README.md', readme, {encoding:'utf-8'}); 14 | 15 | console.log(`README updated ✅`); 16 | }; 17 | 18 | 19 | function updateManifest(newVersion) { 20 | const re = /"version":.*/gm; 21 | 22 | let manifest = fs.readFileSync('./package.json', {encoding:'utf8', flag:'r'}); 23 | 24 | manifest = manifest.replace(re, `"version": "${newVersion}",`); 25 | 26 | fs.writeFileSync('./package.json', manifest, {encoding:'utf-8'}); 27 | 28 | console.log(`Manifest updated ✅`); 29 | }; 30 | 31 | 32 | async function promptChange(changes) { 33 | if (!changes) { 34 | changes = []; 35 | } 36 | 37 | return await inquirer.prompt([ 38 | { 39 | type: 'input', 40 | name: 'change', 41 | message: 'Enter a change for the changelog:', 42 | validate: changeInput => { 43 | if (changeInput) { 44 | return true; 45 | } else { 46 | console.log('Please enter a change!'); 47 | return false; 48 | } 49 | } 50 | }, 51 | { 52 | type: 'confirm', 53 | name: 'confirmAddChange', 54 | message: 'Would you like to enter another change?', 55 | default: false 56 | } 57 | ]) 58 | .then((answers) => { 59 | changes.push(answers.change); 60 | if (answers.confirmAddChange) { 61 | return promptChange(changes); 62 | } else { 63 | return changes; 64 | } 65 | }) 66 | .catch((error) => { 67 | if (error.isTtyError) { 68 | console.log("Prompt couldn't be rendered in the current environment"); 69 | } else { 70 | console.log(error); 71 | } 72 | }); 73 | }; 74 | 75 | 76 | async function updateChangelog(newVersion) { 77 | 78 | const changes = await promptChange(); 79 | 80 | let logText = `## [${newVersion}] \n \n`; 81 | 82 | changes.forEach((change) => { 83 | logText += `- ${change} \n \n`; 84 | }); 85 | 86 | let changelog = fs.readFileSync('./CHANGELOG.md', {encoding:'utf8', flag:'r'}); 87 | 88 | changelog = logText + changelog; 89 | 90 | fs.writeFileSync('./CHANGELOG.md', changelog, {encoding:'utf-8'}); 91 | 92 | console.log(`Changelog updated ✅`); 93 | 94 | }; 95 | 96 | 97 | async function upver() { 98 | const newVersion = process.argv[4]; 99 | 100 | try { 101 | updateReadme(newVersion); 102 | updateManifest(newVersion); 103 | await updateChangelog(newVersion); 104 | } 105 | catch(err){ 106 | console.log(err); 107 | } 108 | } 109 | 110 | 111 | exports.upver = upver; -------------------------------------------------------------------------------- /src/color.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | 3 | import { showNotification } from './extension'; 4 | 5 | export class ColorProvider implements vscode.WebviewViewProvider { 6 | private _view?: vscode.WebviewView; 7 | private selectedColor: any; 8 | 9 | constructor( 10 | private readonly _extensionUri: vscode.Uri, 11 | private readonly colorStatusBarItem: any 12 | ) {} 13 | 14 | public resolveWebviewView(webviewView: vscode.WebviewView) { 15 | this._view = webviewView; 16 | 17 | webviewView.webview.options = { 18 | enableScripts: true, 19 | localResourceRoots: [this._extensionUri], 20 | }; 21 | 22 | webviewView.webview.html = this._getHtmlForWebview(webviewView.webview); 23 | 24 | webviewView.webview.onDidReceiveMessage((data) => { 25 | if (data.type == 'updateSelectedColor') { 26 | this.selectedColor = data.value; 27 | this.colorStatusBarItem.update(data.value); 28 | } 29 | }); 30 | } 31 | 32 | public copySelectedColor() { 33 | vscode.env.clipboard.writeText(this.selectedColor); 34 | showNotification('copied ' + this.selectedColor); 35 | } 36 | 37 | public setSelectedColor(color: string) { 38 | if (this._view) { 39 | this._view.webview.postMessage({ 40 | type: 'setSelectedColor', 41 | value: color, 42 | }); 43 | } 44 | } 45 | 46 | private _getHtmlForWebview(webview: vscode.Webview) { 47 | const main = webview.asWebviewUri( 48 | vscode.Uri.joinPath(this._extensionUri, 'media', 'main.js') 49 | ); 50 | 51 | const colorWheel = webview.asWebviewUri( 52 | vscode.Uri.joinPath(this._extensionUri, 'media', 'lib', 'reinvented-color-wheel.min.js') 53 | ); 54 | const styleColorWheel = webview.asWebviewUri( 55 | vscode.Uri.joinPath( 56 | this._extensionUri, 57 | 'media', 58 | 'lib', 59 | 'reinvented-color-wheel.css' 60 | ) 61 | ); 62 | 63 | const nonce = getNonce(); 64 | 65 | return ` 66 | 67 | 68 | 69 | 70 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 |
83 | 84 | 85 | 86 | 87 | `; 88 | } 89 | } 90 | 91 | function getNonce() { 92 | let text = ''; 93 | const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; 94 | for (let i = 0; i < 32; i++) { 95 | text += possible.charAt(Math.floor(Math.random() * possible.length)); 96 | } 97 | return text; 98 | } 99 | 100 | // 101 | // 102 | // 103 | -------------------------------------------------------------------------------- /resources/light/clear.svg: -------------------------------------------------------------------------------- 1 | 2 | image/svg+xml 43 | 44 | 47 | 48 | 51 | 52 | 55 | 56 | 59 | 60 | 63 | 64 | 67 | 68 | 71 | 72 | 75 | 76 | 79 | 80 | 83 | 84 | 87 | 88 | 91 | 92 | 95 | 96 | 99 | 100 | 103 | 104 | -------------------------------------------------------------------------------- /resources/light/edit.svg: -------------------------------------------------------------------------------- 1 | 2 | image/svg+xml 43 | 47 | 52 | 53 | 56 | 57 | 60 | 61 | 64 | 65 | 68 | 69 | 72 | 73 | 76 | 77 | 80 | 81 | 84 | 85 | 88 | 89 | 92 | 93 | 96 | 97 | 100 | 101 | 104 | 105 | 108 | 109 | 112 | 113 | -------------------------------------------------------------------------------- /resources/dark/edit.svg: -------------------------------------------------------------------------------- 1 | 2 | image/svg+xml 43 | 47 | 52 | 53 | 56 | 57 | 60 | 61 | 64 | 65 | 68 | 69 | 72 | 73 | 76 | 77 | 80 | 81 | 84 | 85 | 88 | 89 | 92 | 93 | 96 | 97 | 100 | 101 | 104 | 105 | 108 | 109 | 112 | 113 | -------------------------------------------------------------------------------- /resources/dark/clear.svg: -------------------------------------------------------------------------------- 1 | 2 | image/svg+xml 43 | 44 | 47 | 48 | 51 | 52 | 55 | 56 | 59 | 60 | 63 | 64 | 67 | 68 | 71 | 72 | 75 | 76 | 79 | 80 | 83 | 84 | 87 | 88 | 91 | 92 | 95 | 96 | 99 | 100 | 103 | 104 | -------------------------------------------------------------------------------- /resources/dark/view.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 21 | 25 | 29 | 30 | 49 | 51 | 52 | 54 | image/svg+xml 55 | 57 | 58 | 59 | 60 | 61 | 66 | 74 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /resources/light/view.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 21 | 25 | 29 | 30 | 49 | 51 | 52 | 54 | image/svg+xml 55 | 57 | 58 | 59 | 60 | 61 | 66 | 74 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /src/extension.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | import * as vscode from 'vscode'; 3 | 4 | import { clearCache } from './utils/cache'; 5 | 6 | import { getConfig } from './configuration'; 7 | import { ElementProvider, ViewMode, getEffectiveColor } from './elements'; 8 | import { InfoProvider } from './info'; 9 | import { ColorProvider } from './color'; 10 | import { TargetingModeStatusBarItem, ColorStatusBarItem } from './statusbar'; 11 | 12 | let infoProvider: InfoProvider; 13 | 14 | const config = getConfig(); 15 | 16 | /** 17 | * Called when the extension is first activated. 18 | */ 19 | export function activate(context: vscode.ExtensionContext) { 20 | const registerCommand = vscode.commands.registerCommand; 21 | 22 | const targetingModeStatusBarItem = new TargetingModeStatusBarItem(); 23 | registerCommand('toggleTargetingMode', () => config.toggleTargetingMode()); 24 | targetingModeStatusBarItem.update(config.getTargetingMode()); 25 | 26 | const colorStatusBarItem = new ColorStatusBarItem(); 27 | 28 | infoProvider = new InfoProvider(); 29 | vscode.window.registerTreeDataProvider('codeui.views.info', infoProvider); 30 | 31 | const elementProvider: ElementProvider = new ElementProvider(ViewMode.standard); 32 | vscode.window.registerTreeDataProvider('codeui.views.elements', elementProvider); 33 | registerCommand('customize', (element) => elementProvider.customize(element)); 34 | registerCommand('adjustBrightness', (element) => elementProvider.adjustBrightness(element)); 35 | registerCommand('clear', (element) => elementProvider.clear(element)); 36 | registerCommand('copy', (element) => elementProvider.copy(element)); 37 | registerCommand('toggleViewMode', () => elementProvider.toggleViewMode()); 38 | 39 | const colorProvider = new ColorProvider(context.extensionUri, colorStatusBarItem); 40 | context.subscriptions.push( 41 | vscode.window.registerWebviewViewProvider('codeui.views.color', colorProvider) 42 | ); 43 | registerCommand('copySelectedColor', () => colorProvider.copySelectedColor()); 44 | 45 | registerCommand('updateSelectedElement', (element) => { 46 | infoProvider.updateSelectedElement(element); 47 | const color = element.effectiveColor; 48 | if (color) { 49 | colorProvider.setSelectedColor(color); 50 | } 51 | }); 52 | 53 | context.subscriptions.push( 54 | vscode.workspace.onDidChangeConfiguration((e) => { 55 | if (e.affectsConfiguration('codeui.targetingMode')) { 56 | const config = getConfig(); 57 | const targetingMode = config.getTargetingMode(); 58 | targetingModeStatusBarItem.update(targetingMode); 59 | } 60 | if ( 61 | e.affectsConfiguration('workbench.colorTheme') || 62 | e.affectsConfiguration('workbench.colorCustomizations') 63 | ) { 64 | elementProvider.refresh(); 65 | infoProvider.updateTheme(); 66 | infoProvider.refresh(); 67 | } 68 | }) 69 | ); 70 | } 71 | 72 | /** 73 | * Called when the extension is deactivated. 74 | */ 75 | export function deactivate() { 76 | clearCache(__filename); 77 | } 78 | 79 | /** 80 | * Shows a dialog allowing the user to choose a scope. 81 | */ 82 | export async function chooseScope(workspaceFolder: vscode.WorkspaceFolder) { 83 | const result = await vscode.window.showQuickPick( 84 | [ 85 | { label: 'Global', target: vscode.ConfigurationTarget.Global }, 86 | { 87 | label: `Workspace (${workspaceFolder.name})`, 88 | target: vscode.ConfigurationTarget.Workspace, 89 | }, 90 | ], 91 | { placeHolder: 'Select a target...' } 92 | ); 93 | if (result) { 94 | return result.target; 95 | } 96 | } 97 | 98 | /** 99 | * Shows a notification from CodeUI. 100 | */ 101 | export async function showNotification(message: string) { 102 | const isEnabled = await vscode.workspace.getConfiguration().get('codeui.showNotifications'); 103 | if (isEnabled === true) { 104 | vscode.window.showInformationMessage('CodeUI: ' + message); 105 | } else { 106 | return; 107 | } 108 | } 109 | 110 | /** 111 | * Gets the current Info view provider instance. 112 | */ 113 | export function getInfoProvider() { 114 | return infoProvider; 115 | } 116 | -------------------------------------------------------------------------------- /resources/activityBar/wireframe-swatch.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 21 | 44 | 46 | 47 | 49 | image/svg+xml 50 | 52 | 53 | 54 | 55 | 56 | 61 | 65 | 71 | 72 | 73 | 78 | 82 | 86 | 92 | 93 | 94 | 95 | 96 | -------------------------------------------------------------------------------- /resources/activityBar/wireframe-swatch-thicc.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 21 | 44 | 46 | 47 | 49 | image/svg+xml 50 | 52 | 53 | 54 | 55 | 56 | 61 | 65 | 71 | 72 | 73 | 78 | 82 | 86 | 92 | 93 | 94 | 95 | 96 | -------------------------------------------------------------------------------- /resources/activityBar/activityBar.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 21 | 40 | 42 | 43 | 45 | image/svg+xml 46 | 48 | 49 | 50 | 51 | 52 | 56 | 61 | 62 | 66 | 69 | 73 | 78 | 79 | 80 | 81 | 85 | 86 | -------------------------------------------------------------------------------- /.vscode/.ropeproject/config.py: -------------------------------------------------------------------------------- 1 | # The default ``config.py`` 2 | # flake8: noqa 3 | 4 | 5 | def set_prefs(prefs): 6 | """This function is called before opening the project""" 7 | 8 | # Specify which files and folders to ignore in the project. 9 | # Changes to ignored resources are not added to the history and 10 | # VCSs. Also they are not returned in `Project.get_files()`. 11 | # Note that ``?`` and ``*`` match all characters but slashes. 12 | # '*.pyc': matches 'test.pyc' and 'pkg/test.pyc' 13 | # 'mod*.pyc': matches 'test/mod1.pyc' but not 'mod/1.pyc' 14 | # '.svn': matches 'pkg/.svn' and all of its children 15 | # 'build/*.o': matches 'build/lib.o' but not 'build/sub/lib.o' 16 | # 'build//*.o': matches 'build/lib.o' and 'build/sub/lib.o' 17 | prefs['ignored_resources'] = ['*.pyc', '*~', '.ropeproject', 18 | '.hg', '.svn', '_svn', '.git', '.tox'] 19 | 20 | # Specifies which files should be considered python files. It is 21 | # useful when you have scripts inside your project. Only files 22 | # ending with ``.py`` are considered to be python files by 23 | # default. 24 | # prefs['python_files'] = ['*.py'] 25 | 26 | # Custom source folders: By default rope searches the project 27 | # for finding source folders (folders that should be searched 28 | # for finding modules). You can add paths to that list. Note 29 | # that rope guesses project source folders correctly most of the 30 | # time; use this if you have any problems. 31 | # The folders should be relative to project root and use '/' for 32 | # separating folders regardless of the platform rope is running on. 33 | # 'src/my_source_folder' for instance. 34 | # prefs.add('source_folders', 'src') 35 | 36 | # You can extend python path for looking up modules 37 | # prefs.add('python_path', '~/python/') 38 | 39 | # Should rope save object information or not. 40 | prefs['save_objectdb'] = True 41 | prefs['compress_objectdb'] = False 42 | 43 | # If `True`, rope analyzes each module when it is being saved. 44 | prefs['automatic_soa'] = True 45 | # The depth of calls to follow in static object analysis 46 | prefs['soa_followed_calls'] = 0 47 | 48 | # If `False` when running modules or unit tests "dynamic object 49 | # analysis" is turned off. This makes them much faster. 50 | prefs['perform_doa'] = True 51 | 52 | # Rope can check the validity of its object DB when running. 53 | prefs['validate_objectdb'] = True 54 | 55 | # How many undos to hold? 56 | prefs['max_history_items'] = 32 57 | 58 | # Shows whether to save history across sessions. 59 | prefs['save_history'] = True 60 | prefs['compress_history'] = False 61 | 62 | # Set the number spaces used for indenting. According to 63 | # :PEP:`8`, it is best to use 4 spaces. Since most of rope's 64 | # unit-tests use 4 spaces it is more reliable, too. 65 | prefs['indent_size'] = 4 66 | 67 | # Builtin and c-extension modules that are allowed to be imported 68 | # and inspected by rope. 69 | prefs['extension_modules'] = [] 70 | 71 | # Add all standard c-extensions to extension_modules list. 72 | prefs['import_dynload_stdmods'] = True 73 | 74 | # If `True` modules with syntax errors are considered to be empty. 75 | # The default value is `False`; When `False` syntax errors raise 76 | # `rope.base.exceptions.ModuleSyntaxError` exception. 77 | prefs['ignore_syntax_errors'] = False 78 | 79 | # If `True`, rope ignores unresolvable imports. Otherwise, they 80 | # appear in the importing namespace. 81 | prefs['ignore_bad_imports'] = False 82 | 83 | # If `True`, rope will insert new module imports as 84 | # `from import ` by default. 85 | prefs['prefer_module_from_imports'] = False 86 | 87 | # If `True`, rope will transform a comma list of imports into 88 | # multiple separate import statements when organizing 89 | # imports. 90 | prefs['split_imports'] = False 91 | 92 | # If `True`, rope will remove all top-level import statements and 93 | # reinsert them at the top of the module when making changes. 94 | prefs['pull_imports_to_top'] = True 95 | 96 | # If `True`, rope will sort imports alphabetically by module name instead 97 | # of alphabetically by import statement, with from imports after normal 98 | # imports. 99 | prefs['sort_imports_alphabetically'] = False 100 | 101 | # Location of implementation of 102 | # rope.base.oi.type_hinting.interfaces.ITypeHintingFactory In general 103 | # case, you don't have to change this value, unless you're an rope expert. 104 | # Change this value to inject you own implementations of interfaces 105 | # listed in module rope.base.oi.type_hinting.providers.interfaces 106 | # For example, you can add you own providers for Django Models, or disable 107 | # the search type-hinting in a class hierarchy, etc. 108 | prefs['type_hinting_factory'] = ( 109 | 'rope.base.oi.type_hinting.factory.default_type_hinting_factory') 110 | 111 | 112 | def project_opened(project): 113 | """This function is called after opening the project""" 114 | # Do whatever you like here! 115 | -------------------------------------------------------------------------------- /src/info.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | import { Element } from './elements'; 3 | 4 | import * as theme from './theme'; 5 | 6 | export class InfoProvider implements vscode.TreeDataProvider { 7 | private _onDidChangeTreeData: vscode.EventEmitter = new vscode.EventEmitter(); 8 | readonly onDidChangeTreeData: vscode.Event = this._onDidChangeTreeData.event; 9 | 10 | currentTheme: any; 11 | selectedElement: any; 12 | 13 | elementHeading: InfoItem | undefined; 14 | themeHeading: any; 15 | 16 | constructor() { 17 | this.updateTheme(); 18 | } 19 | 20 | refresh(infoItem?: any) { 21 | if (infoItem) { 22 | this._onDidChangeTreeData.fire(infoItem); 23 | } else { 24 | this._onDidChangeTreeData.fire(null); 25 | } 26 | } 27 | 28 | getTreeItem(element: vscode.TreeItem): vscode.TreeItem { 29 | return element; 30 | } 31 | 32 | getChildren(infoItem?: InfoItem): vscode.TreeItem[] { 33 | let children: Array = []; 34 | 35 | if (!infoItem) { 36 | // If root... 37 | children.push(this.getThemeItem()); 38 | children.push(this.getSelectedElementItem()); 39 | } else { 40 | if (infoItem.label === 'Theme') { 41 | // If theme section... 42 | children = this.getThemeChildren(); 43 | } 44 | if (infoItem.label === 'Element') { 45 | // If element section... 46 | children = this.getSelectedElementChildren(); 47 | } 48 | } 49 | 50 | return children; 51 | } 52 | 53 | updateSelectedElement(element: Element) { 54 | const selectedElement = element; 55 | this.selectedElement = selectedElement; 56 | this.refresh(); 57 | } 58 | 59 | getSelectedElementItem(): InfoItem { 60 | if (!this.selectedElement) { 61 | return new InfoItem({ 62 | label: 'Element', 63 | description: '-', 64 | collapsibleState: vscode.TreeItemCollapsibleState.Expanded, 65 | }); 66 | } 67 | const selectedElementHeading = new InfoItem({ 68 | label: 'Element', 69 | description: this.selectedElement.elementData['titleName'], 70 | collapsibleState: vscode.TreeItemCollapsibleState.Expanded, 71 | }); 72 | return selectedElementHeading; 73 | } 74 | 75 | getSelectedElementChildren(): Array { 76 | if (!this.selectedElement) { 77 | return []; 78 | } 79 | 80 | const selectedElementChildren: Array = []; 81 | 82 | selectedElementChildren.push( 83 | new InfoItem({ 84 | label: 'Default', 85 | description: definitionToLowerCaseDescription( 86 | this.selectedElement.colorConfig.default 87 | ), 88 | collapsibleState: vscode.TreeItemCollapsibleState.None, 89 | }) 90 | ); 91 | selectedElementChildren.push( 92 | new InfoItem({ 93 | label: 'Theme', 94 | description: definitionToLowerCaseDescription( 95 | this.selectedElement.colorConfig.theme 96 | ), 97 | collapsibleState: vscode.TreeItemCollapsibleState.None, 98 | }) 99 | ); 100 | selectedElementChildren.push( 101 | new InfoItem({ 102 | label: 'Settings (global)', 103 | description: definitionToLowerCaseDescription( 104 | this.selectedElement.colorConfig.settings.global 105 | ), 106 | collapsibleState: vscode.TreeItemCollapsibleState.None, 107 | }) 108 | ); 109 | selectedElementChildren.push( 110 | new InfoItem({ 111 | label: 'Settings (workspace)', 112 | description: definitionToLowerCaseDescription( 113 | this.selectedElement.colorConfig.settings.workspace 114 | ), 115 | collapsibleState: vscode.TreeItemCollapsibleState.None, 116 | }) 117 | ); 118 | 119 | return selectedElementChildren; 120 | } 121 | 122 | updateTheme() { 123 | const currentTheme = theme.getCurrentColorTheme(); 124 | this.currentTheme = currentTheme; 125 | } 126 | 127 | getThemeItem(): InfoItem { 128 | if (!this.currentTheme) { 129 | return new InfoItem({ 130 | label: 'Theme', 131 | description: '-', 132 | collapsibleState: vscode.TreeItemCollapsibleState.None, 133 | }); 134 | } 135 | const themeHeading = new InfoItem({ 136 | label: 'Theme', 137 | description: this.currentTheme.name, 138 | collapsibleState: vscode.TreeItemCollapsibleState.Collapsed, 139 | }); 140 | return themeHeading; 141 | } 142 | 143 | getThemeChildren(): Array { 144 | //Update description of theme header and return array of it's children 145 | 146 | if (!this.currentTheme) { 147 | return []; 148 | } 149 | 150 | const themeInfoChildren: Array = []; 151 | 152 | themeInfoChildren.push( 153 | new InfoItem({ 154 | label: 'Type', 155 | description: this.currentTheme.type, 156 | collapsibleState: vscode.TreeItemCollapsibleState.None, 157 | }) 158 | ); 159 | themeInfoChildren.push( 160 | new InfoItem({ 161 | label: 'Author', 162 | description: this.currentTheme.author, 163 | collapsibleState: vscode.TreeItemCollapsibleState.None, 164 | }) 165 | ); 166 | 167 | return themeInfoChildren; 168 | } 169 | } 170 | 171 | class InfoItem extends vscode.TreeItem { 172 | iconPath: any; 173 | description: any; 174 | 175 | constructor({ 176 | label, 177 | description, 178 | collapsibleState, 179 | }: { 180 | label: string; 181 | description: string; 182 | collapsibleState: vscode.TreeItemCollapsibleState; 183 | }) { 184 | super(label, collapsibleState); 185 | this.description = description; 186 | } 187 | } 188 | 189 | function definitionToLowerCaseDescription(value: any): string { 190 | if (value && typeof value === 'string') { 191 | return value.toLowerCase(); 192 | } else { 193 | return '-'; 194 | } 195 | } 196 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "codeui", 3 | "displayName": "CodeUI", 4 | "publisher": "ryanraposo", 5 | "license": "SEE LICENSE IN LICENSE.md", 6 | "description": "Customize your color theme for VS Code.", 7 | "icon": "resources/marketplace/codeui-128.png", 8 | "version": "1.1.0", 9 | "preview": false, 10 | "galleryBanner": { 11 | "color": "#18191e", 12 | "theme": "dark" 13 | }, 14 | "engines": { 15 | "vscode": "^1.50.0" 16 | }, 17 | "extensionKind": [ 18 | "ui", 19 | "workspace" 20 | ], 21 | "categories": [ 22 | "Other" 23 | ], 24 | "keywords": [ 25 | "theme", 26 | "editor", 27 | "color", 28 | "UI", 29 | "customize" 30 | ], 31 | "activationEvents": [ 32 | "onView:codeui.views.elements", 33 | "onView:codeui.views.info", 34 | "onView:codeui.views.color" 35 | ], 36 | "main": "./out/extension.js", 37 | "contributes": { 38 | "configuration": { 39 | "title": "CodeUI", 40 | "properties": { 41 | "codeui.showNotifications": { 42 | "type": "boolean", 43 | "default": true, 44 | "description": "Controls the display of various notifications by CodeUI. Default is true." 45 | }, 46 | "codeui.favoriteColors": { 47 | "type": "object", 48 | "patternProperties": { 49 | ".+": { 50 | "format": "color", 51 | "type": "string" 52 | } 53 | }, 54 | "default": {}, 55 | "description": "User-defined colors for use by CodeUI (eg. \"Clay\" : \"#F28585\")" 56 | }, 57 | "codeui.targetingMode": { 58 | "type": "string", 59 | "enum": [ 60 | "themeSpecific", 61 | "general" 62 | ], 63 | "default": "themeSpecific", 64 | "description": "Controls context of customizations applied by CodeUI. Default is 'themeSpecific'", 65 | "scope": "application" 66 | }, 67 | "codeui.preferredScope": { 68 | "description": "Controls scoping behaviour when a workspace/folder is open. Default is 'alwaysAsk'", 69 | "type": "string", 70 | "enum": [ 71 | "alwaysAsk", 72 | "global", 73 | "workspace" 74 | ], 75 | "default": "alwaysAsk" 76 | } 77 | } 78 | }, 79 | "commands": [ 80 | { 81 | "command": "toggleTargetingMode", 82 | "title": "CodeUI: Toggle targeting mode" 83 | }, 84 | { 85 | "command": "toggleViewMode", 86 | "title": "Toggle Standard/Palette view", 87 | "icon": { 88 | "light": "resources/light/view.svg", 89 | "dark": "resources/dark/view.svg" 90 | } 91 | }, 92 | { 93 | "command": "adjustBrightness", 94 | "title": "Adjust brightness...", 95 | "icon": { 96 | "light": "resources/light/brightness.svg", 97 | "dark": "resources/dark/brightness.svg" 98 | } 99 | }, 100 | { 101 | "command": "customize", 102 | "title": "Customize...", 103 | "icon": { 104 | "light": "resources/light/edit.svg", 105 | "dark": "resources/dark/edit.svg" 106 | } 107 | }, 108 | { 109 | "command": "clear", 110 | "title": "Delete customizations...", 111 | "icon": { 112 | "light": "resources/light/clear.svg", 113 | "dark": "resources/dark/clear.svg" 114 | } 115 | }, 116 | { 117 | "command": "copy", 118 | "title": "Copy" 119 | }, 120 | { 121 | "command": "copySelectedColor", 122 | "title": "CodeUI: Copy selection from picker", 123 | "icon": "$(symbol-reference)" 124 | } 125 | ], 126 | "viewsContainers": { 127 | "activitybar": [ 128 | { 129 | "id": "codeui", 130 | "title": "CodeUI", 131 | "icon": "resources/activityBar/wireframe-swatch-thicc.svg" 132 | } 133 | ] 134 | }, 135 | "views": { 136 | "codeui": [ 137 | { 138 | "id": "codeui.views.info", 139 | "name": "Info" 140 | }, 141 | { 142 | "id": "codeui.views.elements", 143 | "name": "Elements" 144 | }, 145 | { 146 | "id": "codeui.views.color", 147 | "name": "Color", 148 | "type": "webview" 149 | } 150 | ] 151 | }, 152 | "menus": { 153 | "view/title": [ 154 | { 155 | "command": "toggleViewMode", 156 | "when": "view == codeui.views.elements", 157 | "group": "navigation" 158 | } 159 | ], 160 | "view/item/context": [ 161 | { 162 | "command": "clear", 163 | "when": "viewItem != standardGroup && view == codeui.views.elements", 164 | "group": "inline" 165 | }, 166 | { 167 | "command": "customize", 168 | "when": "viewItem != standardGroup && view == codeui.views.elements", 169 | "group": "inline" 170 | }, 171 | { 172 | "command": "adjustBrightness", 173 | "when": "viewItem != standardGroup && view == codeui.views.elements", 174 | "group": "inline" 175 | }, 176 | { 177 | "command": "copy", 178 | "when": "viewItem != standardGroup && view == codeui.views.elements" 179 | } 180 | ] 181 | } 182 | }, 183 | "scripts": { 184 | "vscode:prepublish": "npm run compile", 185 | "compile": "tsc -p ./", 186 | "watch": "tsc -watch -p ./", 187 | "pretest": "npm run compile", 188 | "test": "node ./out/test/runTest.js", 189 | "lint": "eslint -c .eslintrc.js --ext .ts src" 190 | }, 191 | "devDependencies": { 192 | "@types/node": "^14.14.8", 193 | "@types/vscode": "^1.50.0", 194 | "@typescript-eslint/eslint-plugin": "^4.8.2", 195 | "@typescript-eslint/parser": "^4.8.2", 196 | "@vscode/test-electron": "^2.1.3", 197 | "eslint": "^7.14.0", 198 | "eslint-config-prettier": "^6.15.0", 199 | "eslint-config-standard": "^16.0.2", 200 | "eslint-plugin-import": "^2.22.1", 201 | "eslint-plugin-node": "^11.1.0", 202 | "eslint-plugin-prettier": "^3.1.4", 203 | "eslint-plugin-promise": "^4.2.1", 204 | "eslint-plugin-standard": "^5.0.0", 205 | "gulp": "^4.0.2", 206 | "inquirer": "^8.2.4", 207 | "prettier": "^2.2.0", 208 | "typescript": "^4.0.5" 209 | }, 210 | "dependencies": { 211 | "@ctrl/tinycolor": "^3.1.7", 212 | "jsonc-parser": "^2.3.1" 213 | }, 214 | "repository": { 215 | "type": "git", 216 | "url": "https://github.com/ryanraposo/codeui" 217 | } 218 | } 219 | -------------------------------------------------------------------------------- /media/lib/reinvented-color-wheel.min.js: -------------------------------------------------------------------------------- 1 | var ReinventedColorWheel=function(){"use strict" 2 | var e=function(e){var t=e[0],n=e[1]/100,h=e[2]/100 3 | return 0===h?[0,0,0]:[t,2*(n*=(h*=2)<=1?h:2-h)/(h+n)*100,(h+n)/2*100]},t=function(e){var t,n,h=e[0],i=e[1]/100,r=e[2]/100 4 | return t=i*r,[h,100*(t=(t/=(n=(2-i)*r)<=1?n:2-n)||0),100*(n/=2)]} 5 | function n(e){var t=e[0],n=e[1],h=e[2],i=Math.max(t,n,h),r=i-Math.min(t,n,h),s=r&&60*(i===t?(n-h)/r%6:i===n?(h-t)/r+2:(t-n)/r+4) 6 | return[s<0?s+360:s,i&&100*r/i,100*i/255]}function h(e){var t=e[0]/60,n=e[1]/100,h=e[2]/100,i=h*n,r=h-i,s=255*(i*(1-Math.abs(t%2-1))+r)+.5|0,a=255*(i+r)+.5|0,o=255*r+.5|0,l=0|t 7 | return 1===l?[s,a,o]:2===l?[o,a,s]:3===l?[o,s,a]:4===l?[s,o,a]:5===l?[a,o,s]:[a,s,o]}function i(e){var t,n=Math.round((t=e,0,255,Math.min(Math.max(t,0),255))).toString(16) 8 | return 1==n.length?"0"+n:n}var r=function(e){var t=4===e.length?i(255*e[3]):"" 9 | return"#"+i(e[0])+i(e[1])+i(e[2])+t},s=function(e){4!==e.length&&5!==e.length||(e=function(e){for(var t="#",n=1;n100?100:(10*e+.5|0)/10}function c(e){return"number"==typeof e&&isFinite(e)}var v="PointerEvent"in window?function(e,t,n){e.addEventListener("pointerdown",(function(e){0===e.button&&!1!==t(e)&&this.setPointerCapture(e.pointerId)})),e.addEventListener("pointermove",(function(e){this.hasPointerCapture(e.pointerId)&&n(e)}))}:"ontouchend"in window?function(e,t,n){var h=!1 16 | e.addEventListener("touchstart",(function(e){1===e.touches.length&&!1!==t(e.touches[0])&&(h=!0,e.preventDefault())})),e.addEventListener("touchmove",(function(e){h&&1===e.touches.length&&(e.preventDefault(),n(e.touches[0]))}))}:function(e,t,n){var h=function(e){n(e)},i=function(){removeEventListener("mouseup",i),removeEventListener("mousemove",h)} 17 | e.addEventListener("mousedown",(function(e){0===e.button&&!1!==t(e)&&(addEventListener("mousemove",h),addEventListener("mouseup",i))}))},d={hsv:[0,100,100],hsl:[0,100,50],wheelDiameter:200,wheelThickness:20,handleDiameter:16,wheelReflectsSaturation:!0,onChange:function(){}},p=window.DOMMatrix||window.WebKitCSSMatrix||window.MSCSSMatrix 18 | function f(e,t){var n=document.createElement(e) 19 | return n.className=t,n}return function(){function i(e){var t=this 20 | this.options=e,this.wheelDiameter=this.options.wheelDiameter||d.wheelDiameter,this.wheelThickness=this.options.wheelThickness||d.wheelThickness,this.handleDiameter=this.options.handleDiameter||d.handleDiameter,this.onChange=this.options.onChange||d.onChange,this.wheelReflectsSaturation=void 0!==this.options.wheelReflectsSaturation?this.options.wheelReflectsSaturation:d.wheelReflectsSaturation,this.rootElement=this.options.appendTo.appendChild(f("div","reinvented-color-wheel")),this.hueWheelElement=this.rootElement.appendChild(f("canvas","reinvented-color-wheel--hue-wheel")),this.hueWheelContext=this.hueWheelElement.getContext("2d"),this.hueHandleElement=this.rootElement.appendChild(f("div","reinvented-color-wheel--hue-handle")),this.svSpaceElement=this.rootElement.appendChild(f("canvas","reinvented-color-wheel--sv-space")),this.svSpaceContext=this.svSpaceElement.getContext("2d"),this.svHandleElement=this.rootElement.appendChild(f("div","reinvented-color-wheel--sv-handle")),this._redrawHueWheel=function(){t._redrawHueWheelRequested=!1 21 | var e=t.wheelDiameter,n=e/2,h=n-t.wheelThickness/2,i=Math.PI/180,r=t.wheelReflectsSaturation?","+t._hsl[1]+"%,"+t._hsl[2]+"%)":",100%,50%)",s=t.hueWheelContext 22 | s.clearRect(0,0,e,e),s.lineWidth=t.wheelThickness 23 | for(var a=0;a<360;a++)s.beginPath(),s.arc(n,n,h,(a-90.7)*i,(a-89.3)*i),s.strokeStyle="hsl("+a+r,s.stroke()},this.hueWheelContext.imageSmoothingEnabled=!1,this.svSpaceContext.imageSmoothingEnabled=!1,this._hsv=a(e.hsv?e.hsv:e.hsl?i.hsl2hsv(e.hsl):e.rgb?i.rgb2hsv(e.rgb):e.hex?i.rgb2hsv(i.hex2rgb(e.hex)):void 0,d.hsv),this._hsl=o(i.hsv2hsl(this._hsv)),this._rgb=i.hsv2rgb(this._hsv),this._hex=i.rgb2hex(this._rgb) 24 | var n=function(e,n){var h=t._inverseTransform.multiply(new p("matrix(1,0,0,1,"+e+","+n+")")) 25 | return{x:h.e,y:h.f}},h=function(e){t._inverseTransform=function(e){for(var t=[e];e=e.parentElement;)t.push(e) 26 | for(var n=new p,h=t.length-1;h>=0;h--){var i=getComputedStyle(t[h]),r=i.transform 27 | if(r&&"none"!==r){var s=i.transformOrigin.split(" ").map(parseFloat) 28 | n=n.translate(s[0],s[1]).multiply(new p(r)).translate(-s[0],-s[1])}}return n.inverse()}(e) 29 | var h=e.getBoundingClientRect() 30 | t._center=n(h.left+h.width/2,h.top+h.height/2)},r=function(e){var h=n(e.clientX,e.clientY),i=h.x-t._center.x,r=h.y-t._center.y,s=Math.atan2(r,i) 31 | t.hsv=[180*s/Math.PI+90,t.hsv[1],t.hsv[2]]},s=function(e){var h=n(e.clientX,e.clientY),i=100/t.svSpaceElement.width,r=(h.x-t._center.x)*i+50,s=(t._center.y-h.y)*i+50 32 | t.hsv=[t._hsv[0],r,s]},l=function(e){h(t.svSpaceElement),s(e)} 33 | v(this.hueWheelElement,(function(e){h(t.hueWheelElement) 34 | var i=n(e.clientX,e.clientY),s=i.x-t._center.x,a=i.y-t._center.y,o=t.wheelDiameter/2-t.wheelThickness 35 | if(s*s+a*a 2 | 3 | Project logo 4 |

5 | 6 |

CodeUI

7 | 8 |
9 | 10 | ![Version](https://img.shields.io/badge/version-0.1.0-red) 11 | ![License](https://img.shields.io/badge/license-MIT-blue.svg) 12 | 13 |
14 | 15 |

Customize your color theme for VS Code. 16 |

17 | 18 | # Usage 19 | 20 | ## Table of Contents 21 | 22 | - [Usage](#usage) 23 | - [Table of Contents](#table-of-contents) 24 | - [Element Information](#element-information) 25 | - [1 Visualizations & Effective Color](#sup1sup-visualizations--effective-color) 26 | - [2 Tooltip Descriptions](#sup2sup-tooltip-descriptions) 27 | - [3 Info View](#sup3sup-info-view) 28 | - [Viewtypes](#viewtypes) 29 | - [Standard](#standard) 30 | - [Palette](#palette) 31 | - [Customization](#customization) 32 | - [Targeting Mode](#targeting-mode) 33 | - [Commands](#commands) 34 | - [Adjust brightness](#adjust-brightness) 35 | - [Customize](#customize) 36 | - [Delete](#delete) 37 | - [Copy](#copy) 38 | - [Colors](#colors) 39 | - [1 Favorites](#sup1sup-favorites) 40 | - [2 Presets](#sup2sup-presets) 41 | - [Allowable values](#allowable-values) 42 | - [*Acceptable values:*](#acceptable-values) 43 | - [*Unacceptable values:*](#unacceptable-values) 44 | - [Color Picker](#color-picker) 45 | 46 | # Element Information 47 | 48 | ![Element Information](/resources/screenshots/info-numbered-v2.png) 49 | 50 | ## 1 Visualizations & Effective Color 51 | 52 | The icons for each item represent color setting, as well as indicate the source of those settings. If an icon is partially covered, the 'top-coat' always represents a customization (global or workspace) from User Settings. The color underneath, if any, is the next runner-up in this ascending priority scheme: 53 | 54 | Default -> Theme -> Customization (global) -> Customization (workspace) 55 | 56 | In the *Elements* view, items which are inherting color will also display the corresponding hex value. This value is indicative of the item's **effective** color, just like the prominent icon color. 57 | 58 | ## 2 Tooltip Descriptions 59 | 60 | Hover over UI elements to view a description of each. 61 | 62 | *Please submit an issue [here](https://github.com/ryanraposo/codeui/issues/new?assignees=&labels=&template=tooltip-description-report.md&title=%5BTOOLTIP+DESCRIPTION%5D) for any descriptions found to be missing, incomplete, or inaccurate. Thank you!* 63 | 64 | ## 3 Info View 65 | 66 | The *Info view* displays the current theme as defined in your settings, and information about your selection in the *Elements view*. Select an element there to view the colors it is currently inherting. 67 | 68 | # Viewtypes 69 | 70 | ![Viewtypes](./resources/screenshots/viewtypes.png) 71 | 72 | *1 Toggle views with the command button at the top right of the *Elements* view.* 73 | 74 | ## Standard 75 | 76 | Allows browsing by element groups. These groups correspond to different parts of the editor, and their titles form the beginning of the values one might add to User Settings. 77 | 78 | For example, the following value would be found under heading *Activity Bar*, as item *Foreground*: 79 | 80 | ```"activityBar.foreground"``` 81 | 82 | ## Palette 83 | 84 | In this viewtype, elements retain a long form of the name, as items are grouped by color. The configuration above would be listed as *Activity Bar Foreground*, grouped with all elements who share it's effective color. 85 | 86 | This viewtype enables you to make batch changes to elements and alter the palette of the editor as it appears. Palette mode also helps in identifying visible elements whose names you aren't familiar with. Use it to see your theme at a glance. 87 | 88 | # Customization 89 | 90 | ## Targeting Mode 91 | 92 | Use configuration ``'codeui.targetingMode'`` to specify the subject of commands issued using CodeUI's interface. Acceptable values are ``'general'`` or ``'themeSpecific'``. 93 | 94 | By default, customization is ``'themeSpecific'`` as shown below: 95 | 96 | workbench.colorCustomizations: { 97 | "[Default Dark+]" : { 98 | "activityBar.foreground" : "#cccccc" 99 | } 100 | } 101 | 102 | The extension also contributes a toggle button, found on the status bar. It will indicate your current target and allow switching modes with a click: 103 | 104 | ![Targeting Mode](./resources/screenshots/targeting-mode.png) 105 | 106 | ## Commands 107 | 108 | CodeUI features four commands for customizing your editor: 109 | 110 | - Adjust brightness.. 111 | - Customize.. 112 | - Delete customization.. 113 | - Copy* 114 | 115 | In **Standard** mode (below), these commands are accessible via buttons for each individual element: 116 | 117 | *\*Copy is located in the context (right-click) menu.* 118 | 119 | ![Customization - Standard](./resources/screenshots/customization-standard.png) 120 | 121 | In **Palette** mode, the inline commands can be applied to both elements *and* palette groups: 122 | 123 | ![Customization - Palette](./resources/screenshots/customization-palette.png) 124 | 125 | ## Adjust brightness 126 | 127 | - Select an adjustment. (*eg Darken 10%*). Be aware that transparency (alpha) values in the color's hex code may exaggerate/diminish the effects of lightening & darkening. 128 | 129 | - If a workspace is open, choose a customization scope (global/workspace). If no workspace is open, global scope will be assumed. 130 | 131 | - Brightness adjustment(s) applied. 132 | 133 | ## Customize 134 | 135 | - Select a customization method. You can either **Enter a value** or **Choose a preset**: 136 | - **Enter a value...** Input a valid hex color. See more in [colors.](#allowable-values) 137 | 138 | - **Choose a preset...** Select a pre-defined color from a pre-loaded list of over 2k values, or a favorite color added to User Settings -> ```"codeui.favoriteColors"``` 139 | 140 | - If a workspace is open, choose a customization scope (global/workspace). If no workspace is open, global scope will be assumed. 141 | 142 | - Customization(s) applied. 143 | 144 | ## Delete 145 | 146 | - If a workspace is open, choose a customization scope (global or workspace). If no workspace is open, global scope will be assumed. 147 | 148 | - Customization(s) deleted. 149 | 150 | ## Copy 151 | 152 | - The selected item's effective value is copied to clipboard. Reminder: Copy is found in the context (right-click) menu. 153 | 154 | # Colors 155 | 156 | ![Preset colors](./resources/screenshots/preset-colors.png) 157 | 158 | ## 1 Favorites 159 | 160 | Use configuration ``codeui.favoriteColors`` to define a list of custom colors, using the format: 161 | 162 | "codeui.favoriteColors": { 163 | "Ice" : "#cccccc", 164 | "Ryan's Green" : "#50C878", 165 | "Sea Foam" : "#40EDB6", 166 | "The Void" : "#000712", 167 | "Salmon" : "#fa8072" 168 | }, 169 | 170 | A name **must** be entered with each value. They will appear first during selection, with a star to indicate an item is user-defined. 171 | 172 | ## 2 Presets 173 | 174 | A list of 2k+ colors are also provided for use. They will appear below any favorites you have stored. 175 | 176 | ## Allowable values 177 | 178 | Only hexidecimal color values can be used by both vscode and CodeUI. This extends to RGBA hex values. 179 | 180 | ### *Acceptable values:* 181 | 182 | - #f2f2f2 ✔️ 183 | - #6c6f934d ✔️ 184 | - #000000 ✔️ 185 | 186 | ### *Unacceptable values:* 187 | 188 | - (22, 45, 90) ❌ 189 | - purple ❌ 190 | - (11, 22, 33, 0) ❌ 191 | 192 | 193 | *If configuration ``codeui.enableNotifications`` is set to ``true`` (default), you will be notified about problematic values on entry.* 194 | 195 | ## Color Picker 196 | 197 | ![Color picker](resources/screenshots/picker.png) 198 | 199 | Select colors with the color picker, then: 200 | 201 | - Click the colored status bar item OR 202 | - Ctrl + Shift + p : "CodeUI: Copy selection from picker" 203 | 204 | 205 | 206 | 207 | 208 | -------------------------------------------------------------------------------- /data/defaultColors_dark.json: -------------------------------------------------------------------------------- 1 | { 2 | "activityBarBadge.background": "#007acc", 3 | "editor.background": "#1e1e1e", 4 | "editor.foreground": "#d4d4d4", 5 | "editor.inactiveSelectionBackground": "#3a3d41", 6 | "editor.selectionHighlightBackground": "#add6ff26", 7 | "editorIndentGuide.activeBackground": "#707070", 8 | "editorIndentGuide.background": "#404040", 9 | "input.placeholderForeground": "#a6a6a6", 10 | "list.dropBackground": "#383b3d", 11 | "menu.background": "#252526", 12 | "menu.foreground": "#cccccc", 13 | "settings.numberInputBackground": "#292929", 14 | "settings.textInputBackground": "#292929", 15 | "sideBarTitle.foreground": "#bbbbbb", 16 | "statusBarItem.remoteBackground": "#16825d", 17 | "statusBarItem.remoteForeground": "#ffffff", 18 | "activityBar.background": "#333333", 19 | "activityBar.dropBackground": "#ffffff1f", 20 | "activityBar.foreground": "#ffffff", 21 | "activityBar.inactiveForeground": "#ffffff99", 22 | "activityBarBadge.foreground": "#ffffff", 23 | "badge.background": "#4d4d4d", 24 | "badge.foreground": "#ffffff", 25 | "breadcrumb.activeSelectionForeground": "#e0e0e0", 26 | "breadcrumb.background": "#1e1e1e", 27 | "breadcrumb.focusForeground": "#e0e0e0", 28 | "breadcrumb.foreground": "#cccccccc", 29 | "breadcrumbPicker.background": "#252526", 30 | "button.background": "#0e639c", 31 | "button.foreground": "#ffffff", 32 | "button.hoverBackground": "#1177bb", 33 | "debugExceptionWidget.background": "#420b0d", 34 | "debugExceptionWidget.border": "#a31515", 35 | "debugToolBar.background": "#333333", 36 | "descriptionForeground": "#ccccccb3", 37 | "diffEditor.insertedTextBackground": "#9bb95533", 38 | "diffEditor.removedTextBackground": "#ff000033", 39 | "dropdown.background": "#3c3c3c", 40 | "dropdown.border": "#3c3c3c", 41 | "dropdown.foreground": "#f0f0f0", 42 | "editor.findMatchBackground": "#515c6a", 43 | "editor.findMatchHighlightBackground": "#ea5c0055", 44 | "editor.findRangeHighlightBackground": "#3a3d4166", 45 | "editor.focusedStackFrameHighlightBackground": "#7abd7a4d", 46 | "editor.hoverHighlightBackground": "#264f7840", 47 | "editor.lineHighlightBorder": "#282828", 48 | "editor.rangeHighlightBackground": "#ffffff0b", 49 | "editor.selectionBackground": "#264f78", 50 | "editor.snippetFinalTabstopHighlightBorder": "#525252", 51 | "editor.snippetTabstopHighlightBackground": "#7c7c7c4d", 52 | "editor.stackFrameHighlightBackground": "#ffff0033", 53 | "editor.wordHighlightBackground": "#575757b8", 54 | "editor.wordHighlightStrongBackground": "#004972b8", 55 | "editorActiveLineNumber.foreground": "#c6c6c6", 56 | "editorBracketMatch.background": "#0064001a", 57 | "editorBracketMatch.border": "#888888", 58 | "editorCodeLens.foreground": "#999999", 59 | "editorCursor.foreground": "#aeafad", 60 | "editorError.foreground": "#ea4646", 61 | "editorGroup.border": "#444444", 62 | "editorGroup.dropBackground": "#53595d80", 63 | "editorGroupHeader.noTabsBackground": "#1e1e1e", 64 | "editorGroupHeader.tabsBackground": "#252526", 65 | "editorGutter.addedBackground": "#587c0c", 66 | "editorGutter.background": "#1e1e1e", 67 | "editorGutter.commentRangeForeground": "#c5c5c5", 68 | "editorGutter.deletedBackground": "#94151b", 69 | "editorGutter.modifiedBackground": "#0c7d9d", 70 | "editorHint.foreground": "#eeeeeeb3", 71 | "editorHoverWidget.background": "#252526", 72 | "editorHoverWidget.border": "#454545", 73 | "editorHoverWidget.statusBarBackground": "#2c2c2d", 74 | "editorInfo.foreground": "#008000", 75 | "editorLineNumber.activeForeground": "#c6c6c6", 76 | "editorLineNumber.foreground": "#858585", 77 | "editorLink.activeForeground": "#4e94ce", 78 | "editorMarkerNavigation.background": "#2d2d30", 79 | "editorMarkerNavigationError.background": "#ea4646", 80 | "editorMarkerNavigationInfo.background": "#008000", 81 | "editorMarkerNavigationWarning.background": "#4d9e4d", 82 | "editorOverviewRuler.addedForeground": "#007acc99", 83 | "editorOverviewRuler.border": "#7f7f7f4d", 84 | "editorOverviewRuler.bracketMatchForeground": "#a0a0a0", 85 | "editorOverviewRuler.commonContentForeground": "#60606066", 86 | "editorOverviewRuler.currentContentForeground": "#40c8ae80", 87 | "editorOverviewRuler.deletedForeground": "#007acc99", 88 | "editorOverviewRuler.errorForeground": "#ff1212b3", 89 | "editorOverviewRuler.findMatchForeground": "#f6b94db3", 90 | "editorOverviewRuler.incomingContentForeground": "#40a6ff80", 91 | "editorOverviewRuler.infoForeground": "#121288b3", 92 | "editorOverviewRuler.modifiedForeground": "#007acc99", 93 | "editorOverviewRuler.rangeHighlightForeground": "#007acc99", 94 | "editorOverviewRuler.selectionHighlightForeground": "#a0a0a0cc", 95 | "editorOverviewRuler.warningForeground": "#128812b3", 96 | "editorOverviewRuler.wordHighlightForeground": "#a0a0a0cc", 97 | "editorOverviewRuler.wordHighlightStrongForeground": "#c0a0c0cc", 98 | "editorPane.background": "#1e1e1e", 99 | "editorRuler.foreground": "#5a5a5a", 100 | "editorSuggestWidget.background": "#252526", 101 | "editorSuggestWidget.border": "#454545", 102 | "editorSuggestWidget.foreground": "#d4d4d4", 103 | "editorSuggestWidget.highlightForeground": "#0097fb", 104 | "editorSuggestWidget.selectedBackground": "#062f4a", 105 | "editorUnnecessaryCode.opacity": "#000000aa", 106 | "editorWarning.foreground": "#4d9e4d", 107 | "editorWhitespace.foreground": "#e3e4e229", 108 | "editorWidget.background": "#252526", 109 | "editorWidget.border": "#454545", 110 | "errorForeground": "#f48771", 111 | "extensionBadge.remoteBackground": "#007acc", 112 | "extensionBadge.remoteForeground": "#ffffff", 113 | "extensionButton.prominentBackground": "#327e36", 114 | "extensionButton.prominentForeground": "#ffffff", 115 | "extensionButton.prominentHoverBackground": "#28632b", 116 | "focusBorder": "#0e639ccc", 117 | "foreground": "#cccccc", 118 | "gitDecoration.addedResourceForeground": "#81b88b", 119 | "gitDecoration.conflictingResourceForeground": "#6c6cc4", 120 | "gitDecoration.deletedResourceForeground": "#c74e39", 121 | "gitDecoration.ignoredResourceForeground": "#8c8c8c", 122 | "gitDecoration.modifiedResourceForeground": "#e2c08d", 123 | "gitDecoration.submoduleResourceForeground": "#8db9e2", 124 | "gitDecoration.untrackedResourceForeground": "#73c991", 125 | "input.background": "#3c3c3c", 126 | "input.foreground": "#cccccc", 127 | "inputOption.activeBorder": "#007acc", 128 | "inputValidation.errorBackground": "#5a1d1d", 129 | "inputValidation.errorBorder": "#be1100", 130 | "inputValidation.infoBackground": "#063b49", 131 | "inputValidation.infoBorder": "#007acc", 132 | "inputValidation.warningBackground": "#352a05", 133 | "inputValidation.warningBorder": "#b89500", 134 | "list.activeSelectionBackground": "#094771", 135 | "list.activeSelectionForeground": "#ffffff", 136 | "list.errorForeground": "#f88070", 137 | "list.focusBackground": "#062f4a", 138 | "list.highlightForeground": "#0097fb", 139 | "list.hoverBackground": "#2a2d2e", 140 | "list.inactiveSelectionBackground": "#37373d", 141 | "list.invalidItemForeground": "#b89500", 142 | "list.warningForeground": "#4d9e4d", 143 | "listFilterWidget.background": "#653723", 144 | "listFilterWidget.noMatchesOutline": "#be1100", 145 | "listFilterWidget.outline": "#00000000", 146 | "menu.selectionBackground": "#094771", 147 | "menu.selectionForeground": "#ffffff", 148 | "menu.separatorBackground": "#bbbbbb", 149 | "menubar.selectionBackground": "#ffffff1a", 150 | "menubar.selectionForeground": "#cccccc", 151 | "merge.commonContentBackground": "#60606029", 152 | "merge.commonHeaderBackground": "#60606066", 153 | "merge.currentContentBackground": "#40c8ae33", 154 | "merge.currentHeaderBackground": "#40c8ae80", 155 | "merge.incomingContentBackground": "#40a6ff33", 156 | "merge.incomingHeaderBackground": "#40a6ff80", 157 | "notificationCenterHeader.background": "#303031", 158 | "notificationLink.foreground": "#3794ff", 159 | "notifications.background": "#252526", 160 | "notifications.border": "#303031", 161 | "panel.background": "#1e1e1e", 162 | "panel.border": "#80808059", 163 | "panel.dropBackground": "#ffffff1f", 164 | "panelTitle.activeBorder": "#80808059", 165 | "panelTitle.activeForeground": "#e7e7e7", 166 | "panelTitle.inactiveForeground": "#e7e7e799", 167 | "peekView.border": "#007acc", 168 | "peekViewEditor.background": "#001f33", 169 | "peekViewEditor.matchHighlightBackground": "#ff8f0099", 170 | "peekViewEditorGutter.background": "#001f33", 171 | "peekViewResult.background": "#252526", 172 | "peekViewResult.fileForeground": "#ffffff", 173 | "peekViewResult.lineForeground": "#bbbbbb", 174 | "peekViewResult.matchHighlightBackground": "#ea5c004d", 175 | "peekViewResult.selectionBackground": "#3399ff33", 176 | "peekViewResult.selectionForeground": "#ffffff", 177 | "peekViewTitle.background": "#1e1e1e", 178 | "peekViewTitleDescription.foreground": "#ccccccb3", 179 | "peekViewTitleLabel.foreground": "#ffffff", 180 | "pickerGroup.border": "#3f3f46", 181 | "pickerGroup.foreground": "#3794ff", 182 | "progressBar.background": "#0e70c0", 183 | "scrollbar.shadow": "#000000", 184 | "scrollbarSlider.activeBackground": "#bfbfbf66", 185 | "scrollbarSlider.background": "#79797966", 186 | "scrollbarSlider.hoverBackground": "#646464b3", 187 | "settings.checkboxBackground": "#3c3c3c", 188 | "settings.checkboxBorder": "#3c3c3c", 189 | "settings.checkboxForeground": "#f0f0f0", 190 | "settings.dropdownBackground": "#3c3c3c", 191 | "settings.dropdownBorder": "#3c3c3c", 192 | "settings.dropdownForeground": "#f0f0f0", 193 | "settings.dropdownListBorder": "#454545", 194 | "settings.headerForeground": "#e7e7e7", 195 | "settings.modifiedItemIndicator": "#0c7d9d", 196 | "settings.numberInputForeground": "#cccccc", 197 | "settings.textInputForeground": "#cccccc", 198 | "sideBar.background": "#252526", 199 | "sideBar.dropBackground": "#ffffff1f", 200 | "sideBarSectionHeader.background": "#80808033", 201 | "statusBar.background": "#007acc", 202 | "statusBar.debuggingBackground": "#cc6633", 203 | "statusBar.debuggingForeground": "#ffffff", 204 | "statusBar.foreground": "#ffffff", 205 | "statusBar.noFolderBackground": "#68217a", 206 | "statusBar.noFolderForeground": "#ffffff", 207 | "statusBarItem.activeBackground": "#ffffff2e", 208 | "statusBarItem.hoverBackground": "#ffffff1f", 209 | "statusBarItem.prominentBackground": "#00000080", 210 | "statusBarItem.prominentForeground": "#ffffff", 211 | "statusBarItem.prominentHoverBackground": "#0000004d", 212 | "tab.activeBackground": "#1e1e1e", 213 | "tab.activeForeground": "#ffffff", 214 | "tab.activeModifiedBorder": "#3399cc", 215 | "tab.border": "#252526", 216 | "tab.inactiveBackground": "#2d2d2d", 217 | "tab.inactiveForeground": "#ffffff80", 218 | "tab.inactiveModifiedBorder": "#3399cc80", 219 | "tab.unfocusedActiveBackground": "#1e1e1e", 220 | "tab.unfocusedActiveForeground": "#ffffff80", 221 | "tab.unfocusedActiveModifiedBorder": "#3399cc80", 222 | "tab.unfocusedInactiveForeground": "#ffffff40", 223 | "tab.unfocusedInactiveModifiedBorder": "#3399cc40", 224 | "terminal.ansiBlack": "#000000", 225 | "terminal.ansiBlue": "#2472c8", 226 | "terminal.ansiBrightBlack": "#666666", 227 | "terminal.ansiBrightBlue": "#3b8eea", 228 | "terminal.ansiBrightCyan": "#29b8db", 229 | "terminal.ansiBrightGreen": "#23d18b", 230 | "terminal.ansiBrightMagenta": "#d670d6", 231 | "terminal.ansiBrightRed": "#f14c4c", 232 | "terminal.ansiBrightWhite": "#e5e5e5", 233 | "terminal.ansiBrightYellow": "#f5f543", 234 | "terminal.ansiCyan": "#11a8cd", 235 | "terminal.ansiGreen": "#0dbc79", 236 | "terminal.ansiMagenta": "#bc3fbc", 237 | "terminal.ansiRed": "#cd3131", 238 | "terminal.ansiWhite": "#e5e5e5", 239 | "terminal.ansiYellow": "#e5e510", 240 | "terminal.background": "#1e1e1e", 241 | "terminal.border": "#80808059", 242 | "terminal.foreground": "#cccccc", 243 | "terminal.selectionBackground": "#ffffff40", 244 | "textBlockQuote.background": "#7f7f7f1a", 245 | "textBlockQuote.border": "#007acc80", 246 | "textCodeBlock.background": "#0a0a0a66", 247 | "textLink.activeForeground": "#3794ff", 248 | "textLink.foreground": "#3794ff", 249 | "textPreformat.foreground": "#d7ba7d", 250 | "textSeparator.foreground": "#ffffff2e", 251 | "titleBar.activeBackground": "#3c3c3c", 252 | "titleBar.activeForeground": "#cccccc", 253 | "titleBar.inactiveBackground": "#3c3c3c99", 254 | "titleBar.inactiveForeground": "#cccccc99", 255 | "widget.shadow": "#000000" 256 | } -------------------------------------------------------------------------------- /src/elements.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import * as vscode from 'vscode'; 4 | import * as fs from 'fs'; 5 | import * as path from 'path'; 6 | import tinycolor from '@ctrl/tinycolor'; 7 | 8 | import { chooseScope, showNotification, getInfoProvider } from './extension'; 9 | import { getConfig } from './configuration'; 10 | import * as theme from './theme'; 11 | 12 | interface ColorConfig { 13 | [index: number]: string; 14 | default: string | undefined; 15 | theme: string | undefined; 16 | settings: { 17 | global: string | undefined; 18 | workspace: string | undefined; 19 | }; 20 | } 21 | 22 | export enum ViewMode { 23 | standard = 0, 24 | palette = 1, 25 | } 26 | 27 | interface WorkbenchCustomizations { 28 | [key: string]: any; 29 | } 30 | 31 | export class ElementProvider implements vscode.TreeDataProvider { 32 | private _onDidChangeTreeData: vscode.EventEmitter = new vscode.EventEmitter(); 33 | readonly onDidChangeTreeData: vscode.Event = this._onDidChangeTreeData.event; 34 | 35 | viewMode: ViewMode; 36 | 37 | colors: any; 38 | elementData: any = []; 39 | colorConfigs: any; 40 | elementItems: any = []; 41 | 42 | constructor(viewMode: ViewMode) { 43 | this.viewMode = viewMode; 44 | this.loadElementData(); 45 | this.loadColors(); 46 | this.loadColorConfigs(); 47 | 48 | for (const key in this.elementData) { 49 | const elementData = this.elementData[key]; 50 | const treeItem = new Element( 51 | elementData, 52 | vscode.TreeItemCollapsibleState.None, 53 | this.viewMode, 54 | this 55 | ); 56 | this.elementItems[elementData.fullName] = treeItem; 57 | } 58 | } 59 | 60 | refresh(element?: any): void { 61 | this.loadColorConfigs(); 62 | 63 | if (element) { 64 | element.update(); 65 | this._onDidChangeTreeData.fire(element); 66 | } else { 67 | for (const key in this.elementItems) { 68 | this.elementItems[key].update(); 69 | } 70 | this._onDidChangeTreeData.fire(null); 71 | } 72 | } 73 | 74 | getTreeItem(element: Element): vscode.TreeItem { 75 | return element; 76 | } 77 | 78 | getChildren(elementTreeGroup?: any): any { 79 | const children: any = []; 80 | 81 | if (this.viewMode === ViewMode.standard) { 82 | if (elementTreeGroup) { 83 | for (const key in this.elementItems) { 84 | const value = this.elementItems[key]; 85 | if (value.elementData.group === elementTreeGroup.label) { 86 | children.push(value); 87 | } 88 | } 89 | return children; 90 | } else { 91 | return this.getStandardViewGroups(); 92 | } 93 | } 94 | 95 | if (this.viewMode === ViewMode.palette) { 96 | if (elementTreeGroup) { 97 | return elementTreeGroup.children; 98 | } else { 99 | return this.getPaletteViewGroups(); 100 | } 101 | } 102 | } 103 | 104 | toggleViewMode() { 105 | this.viewMode = this.viewMode === ViewMode.standard ? ViewMode.palette : ViewMode.standard; 106 | this.refresh(); 107 | } 108 | 109 | private getUserColors() { 110 | this.colors = {}; 111 | const userColors: any = vscode.workspace.getConfiguration().get('codeui.favoriteColors'); 112 | if (userColors) { 113 | for (const key in userColors) { 114 | const value = userColors[key]; 115 | if (isHexidecimal(value)) { 116 | this.colors[value] = '$(star) ' + key; 117 | } else { 118 | showNotification( 119 | "user-defined color '" + 120 | key + 121 | ':' + 122 | value + 123 | ' is not valid. Refer to the config tooltip' 124 | ); 125 | } 126 | } 127 | } 128 | } 129 | 130 | private loadColors(): any { 131 | this.getUserColors(); 132 | 133 | const presetColorsText = fs.readFileSync( 134 | path.join(__filename, '..', '..', 'data', 'colors.json'), 135 | 'utf8' 136 | ); 137 | const presetColors = JSON.parse(presetColorsText); 138 | for (const key in presetColors) { 139 | const value = presetColors[key]; 140 | if (!this.colors[key]) { 141 | this.colors[key] = value; 142 | } 143 | } 144 | } 145 | 146 | private loadElementData(): any { 147 | const fileText: string = fs.readFileSync( 148 | path.join(__filename, '..', '..', 'data', 'vscodeElementsArray.json'), 149 | 'utf8' 150 | ); 151 | const allElementsObject = JSON.parse(fileText); 152 | for (const key in allElementsObject) { 153 | const value = allElementsObject[key]; 154 | this.elementData[value.fullName] = value; 155 | } 156 | } 157 | 158 | private loadColorConfigs(): any { 159 | const elementNames: string[] = []; 160 | for (const key in this.elementData) { 161 | const value = this.elementData[key]; 162 | elementNames.push(value.fullName); 163 | } 164 | const defaultConfigs = getDefaultConfigs(); 165 | const themeConfigs = getThemeConfigs(); 166 | const settingsConfigs = getSettingsConfigs(); 167 | 168 | this.colorConfigs = appendConfigs( 169 | elementNames, 170 | defaultConfigs, 171 | themeConfigs, 172 | settingsConfigs 173 | ); 174 | 175 | function appendConfigs( 176 | elementNames: string[], 177 | defaultConfigs: any, 178 | themeConfigs: any, 179 | settingsConfigs: any 180 | ): any { 181 | const colorConfigurations: any = {}; 182 | const config = getConfig(); 183 | const currentThemeName = config.getColorThemeName(); 184 | 185 | for (const key in elementNames) { 186 | const element: string = elementNames[key]; 187 | const elementColorConfig: ColorConfig = { 188 | default: undefined, 189 | theme: undefined, 190 | settings: { 191 | global: undefined, 192 | workspace: undefined, 193 | }, 194 | }; 195 | 196 | elementColorConfig.default = defaultConfigs[element]; 197 | 198 | if (themeConfigs) { 199 | elementColorConfig.theme = themeConfigs[element]; 200 | } 201 | 202 | if (settingsConfigs) { 203 | if (settingsConfigs.globalValue) { 204 | elementColorConfig.settings.global = settingsConfigs.globalValue[element]; 205 | // resolve theme-specific value 206 | if (settingsConfigs.globalValue['[' + currentThemeName + ']']) { 207 | const themeSpecificCustomizations = 208 | settingsConfigs.globalValue['[' + currentThemeName + ']']; 209 | if (themeSpecificCustomizations[element]) { 210 | elementColorConfig.settings.global = 211 | themeSpecificCustomizations[element]; 212 | } 213 | } 214 | // resolve theme-specific value 215 | } 216 | if (settingsConfigs.workspaceValue) { 217 | elementColorConfig.settings.workspace = 218 | settingsConfigs.workspaceValue[element]; 219 | // resolve theme-specific value 220 | if (settingsConfigs.workspaceValue['[' + currentThemeName + ']']) { 221 | const themeSpecificCustomizations = 222 | settingsConfigs.workspaceValue['[' + currentThemeName + ']']; 223 | if (themeSpecificCustomizations[element]) { 224 | elementColorConfig.settings.workspace = 225 | themeSpecificCustomizations[element]; 226 | } 227 | } 228 | // resolve theme-specific value 229 | } 230 | } 231 | 232 | colorConfigurations[element] = elementColorConfig; 233 | } 234 | 235 | return colorConfigurations; 236 | } 237 | 238 | function getDefaultConfigs() { 239 | const fileText: string = fs.readFileSync( 240 | path.join(__filename, '..', '..', 'data', 'defaultColors_dark.json'), 241 | 'utf8' 242 | ); 243 | const defaultColorsObject = JSON.parse(fileText); 244 | 245 | return defaultColorsObject; 246 | } 247 | 248 | function getThemeConfigs() { 249 | const currentTheme = theme.getCurrentColorTheme(); 250 | const workbenchCustomizations = currentTheme.workbenchColorCustomizations; 251 | 252 | if (workbenchCustomizations) { 253 | return workbenchCustomizations; 254 | } else { 255 | return {}; 256 | } 257 | } 258 | 259 | function getSettingsConfigs() { 260 | const configurations: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration(); 261 | const workbenchColorCustomizations = configurations.inspect( 262 | 'workbench.colorCustomizations' 263 | ); 264 | 265 | if (workbenchColorCustomizations) { 266 | return workbenchColorCustomizations; 267 | } else { 268 | return {}; 269 | } 270 | } 271 | } 272 | 273 | public getStandardViewGroups(): ElementTreeGroup[] { 274 | const elementGroupNames = []; 275 | const elementTreeGroups: any = []; 276 | 277 | for (const key in this.elementItems) { 278 | const group = this.elementItems[key].elementData.group; 279 | if (elementGroupNames.indexOf(group) < 0) { 280 | elementGroupNames.push(group); 281 | elementTreeGroups.push( 282 | new ElementTreeGroup( 283 | group, 284 | vscode.TreeItemCollapsibleState.Collapsed, 285 | undefined, 286 | '', 287 | ViewMode.standard 288 | ) 289 | ); 290 | } 291 | } 292 | 293 | return elementTreeGroups; 294 | } 295 | 296 | public getPaletteViewGroups(): ElementTreeGroup[] { 297 | const elementColors = []; 298 | let elementTreeGroups = []; 299 | 300 | const colorCount: any = []; 301 | 302 | for (const key in this.elementItems) { 303 | const value = this.elementItems[key].colorConfig; 304 | let effectiveColor = getEffectiveColor(value); 305 | if (effectiveColor) { 306 | effectiveColor = effectiveColor.toLowerCase(); 307 | } 308 | if (elementColors.indexOf(effectiveColor) < 0) { 309 | elementColors.push(effectiveColor); 310 | let label = effectiveColor; 311 | if (!label) { 312 | label = '(unset)'; 313 | } 314 | const elementTreeGroup = new ElementTreeGroup( 315 | label, 316 | vscode.TreeItemCollapsibleState.Collapsed, 317 | effectiveColor, 318 | '', 319 | ViewMode.palette 320 | ); 321 | elementTreeGroup.addChild(this.elementItems[key]); 322 | elementTreeGroups.push(elementTreeGroup); 323 | } else { 324 | elementTreeGroups.find((treeGroup) => { 325 | if (treeGroup.label === effectiveColor) { 326 | treeGroup.addChild(this.elementItems[key]); 327 | } 328 | }); 329 | } 330 | } 331 | 332 | elementTreeGroups = elementTreeGroups.sort((e1, e2) => { 333 | if (e1.children.length > e2.children.length) { 334 | return -1; 335 | } else { 336 | return 1; 337 | } 338 | }); 339 | 340 | return elementTreeGroups; 341 | } 342 | 343 | public customize(item: Element | ElementTreeGroup) { 344 | const targetElements: Array = []; 345 | const colorItems: Array = []; 346 | const customizations: WorkbenchCustomizations = {}; 347 | let userColor: string | undefined; 348 | 349 | // Get preset quickpickItems (colors) 350 | for (const key in this.colors) { 351 | const value = this.colors[key]; 352 | colorItems.push({ label: value, description: key }); 353 | } 354 | 355 | // Parse selected element(s) & if element, pass to InfoProvider 356 | const infoProvider = getInfoProvider(); 357 | if (item instanceof Element) { 358 | targetElements.push(item.elementData.fullName); 359 | infoProvider.updateSelectedElement(item); 360 | } 361 | if (item instanceof ElementTreeGroup) { 362 | for (const child of item.children) { 363 | targetElements.push(child.elementData.fullName); 364 | } 365 | } 366 | 367 | // Get customization value from user 368 | vscode.window 369 | .showQuickPick([{ label: 'Enter a value...' }, { label: 'Choose a preset...' }]) 370 | .then((selection) => { 371 | if (selection) { 372 | if (selection.label === 'Enter a value...') { 373 | vscode.window 374 | .showInputBox({ placeHolder: 'eg. #f2f2f2' }) 375 | .then((selectedColor) => { 376 | if (selectedColor) { 377 | userColor = selectedColor; 378 | apply(); // Write the customization to settings 379 | } 380 | }); 381 | } 382 | if (selection.label === 'Choose a preset...') { 383 | vscode.window 384 | .showQuickPick(colorItems, { canPickMany: false }) 385 | .then((selectedColor) => { 386 | if (selectedColor) { 387 | userColor = selectedColor.description; 388 | apply(); // Write the customization to settings 389 | } 390 | }); 391 | } 392 | } 393 | }); 394 | 395 | function apply() { 396 | for (const element of targetElements) { 397 | customizations[element] = userColor; 398 | } 399 | ElementProvider.updateWorkbenchColors(customizations); 400 | } 401 | } 402 | 403 | public async adjustBrightness(item: Element | ElementTreeGroup) { 404 | if (item instanceof Element) { 405 | const infoProvider = getInfoProvider(); 406 | infoProvider.updateSelectedElement(item); 407 | } 408 | 409 | const darken10 = 'Darken (10%)'; 410 | const lighten10 = 'Lighten (10%)'; 411 | const darkenCustom = 'Darken (Custom value)'; 412 | const lightenCustom = 'Lighten (Custom value)'; 413 | const actionSelection = await vscode.window.showQuickPick([ 414 | darken10, 415 | lighten10, 416 | darkenCustom, 417 | lightenCustom, 418 | ]); 419 | if (!actionSelection) { 420 | return; 421 | } 422 | if (actionSelection === lighten10) { 423 | lighten(item); 424 | } else if (actionSelection === darken10) { 425 | darken(item); 426 | } else if (actionSelection === lightenCustom) { 427 | const lightenCustomValueNumber = await showPercentInput(); 428 | if (!lightenCustomValueNumber) { 429 | return; 430 | } 431 | lighten(item, lightenCustomValueNumber); 432 | } else if (actionSelection === darkenCustom) { 433 | const darkenCustomValueNumber = await showPercentInput(); 434 | if (!darkenCustomValueNumber) { 435 | return; 436 | } 437 | darken(item, darkenCustomValueNumber); 438 | } 439 | 440 | async function showPercentInput(): Promise { 441 | const percentString = await vscode.window.showInputBox({ 442 | prompt: 'Enter a number (Percent)', 443 | validateInput(input: string) { 444 | const percentNumber = parseFloat(input); 445 | if (!isNaN(percentNumber) && isFinite(percentNumber)) { 446 | return ''; 447 | } 448 | return 'Value is not a valid number.'; 449 | }, 450 | }); 451 | if (percentString) { 452 | return parseFloat(percentString); 453 | } 454 | } 455 | 456 | function darken(item: Element | ElementTreeGroup, value = 5) { 457 | const customizations: WorkbenchCustomizations = {}; 458 | 459 | if (item instanceof Element) { 460 | const darkenedValue = 461 | '#' + tinycolor(getEffectiveColor(item.colorConfig)).darken(value).toHex(); 462 | customizations[item.elementData.fullName] = darkenedValue; 463 | } 464 | 465 | if (item instanceof ElementTreeGroup) { 466 | for (const key in item.children) { 467 | const value = item.children[key]; 468 | const darkenedValue = 469 | '#' + tinycolor(getEffectiveColor(value.colorConfig)).darken(value).toHex(); 470 | customizations[value.elementData.fullName] = darkenedValue; 471 | } 472 | } 473 | 474 | ElementProvider.updateWorkbenchColors(customizations); 475 | } 476 | 477 | function lighten(item: Element | ElementTreeGroup, value = 5) { 478 | const customizations: WorkbenchCustomizations = {}; 479 | 480 | if (item instanceof Element) { 481 | const lightenedValue = 482 | '#' + tinycolor(getEffectiveColor(item.colorConfig)).lighten(value).toHex(); 483 | customizations[item.elementData.fullName] = lightenedValue; 484 | } 485 | 486 | if (item instanceof ElementTreeGroup) { 487 | for (const key in item.children) { 488 | const value = item.children[key]; 489 | const lightenedValue = 490 | '#' + 491 | tinycolor(getEffectiveColor(value.colorConfig)).lighten(value).toHex(); 492 | customizations[value.elementData.fullName] = lightenedValue; 493 | } 494 | } 495 | 496 | ElementProvider.updateWorkbenchColors(customizations); 497 | } 498 | } 499 | 500 | public clear(item: Element | ElementTreeGroup) { 501 | if (item instanceof Element) { 502 | const infoProvider = getInfoProvider(); 503 | infoProvider.updateSelectedElement(item); 504 | const elementName: string = item.elementData.fullName; 505 | ElementProvider.updateWorkbenchColors({ [elementName]: undefined }); 506 | } else { 507 | const customizations: any = {}; 508 | for (const element of item.children) { 509 | customizations[element.elementData.fullName] = undefined; 510 | ElementProvider.updateWorkbenchColors(customizations); 511 | } 512 | } 513 | } 514 | 515 | public copy(item: Element): void { 516 | if (typeof item.description === 'string') { 517 | vscode.env.clipboard.writeText(item.description); 518 | showNotification('copied ' + item.description); 519 | } 520 | } 521 | 522 | static async updateWorkbenchColors(customizations: WorkbenchCustomizations) { 523 | const config = getConfig(); 524 | const currentThemeProp = '[' + config.getColorThemeName() + ']'; 525 | const scope = await resolveScope(); 526 | const scopedCustomizations: any = config.getWorkbenchColorCustomizations(scope); 527 | for (const element in customizations) { 528 | const value = customizations[element]; 529 | if ((await isHexidecimal(value)) || value === undefined) { 530 | const targetingMode = config.getTargetingMode(); 531 | if (targetingMode === 'themeSpecific') { 532 | if (scopedCustomizations[currentThemeProp]) { 533 | scopedCustomizations[currentThemeProp][element] = value; 534 | } else { 535 | scopedCustomizations[currentThemeProp] = {}; 536 | scopedCustomizations[currentThemeProp][element] = value; 537 | } 538 | } else { 539 | scopedCustomizations[element] = value; 540 | } 541 | } else { 542 | await showNotification(value + 'is not a valid hex color!'); 543 | return; 544 | } 545 | } 546 | await vscode.workspace 547 | .getConfiguration() 548 | .update('workbench.colorCustomizations', scopedCustomizations, scope); 549 | } 550 | } 551 | 552 | export class Element extends vscode.TreeItem { 553 | contextValue = 'element'; 554 | viewMode: any; 555 | elementData: any; 556 | colorConfig: any; 557 | dataProvider: any; 558 | 559 | constructor( 560 | elementData: any, 561 | collapsibleState: vscode.TreeItemCollapsibleState, 562 | viewMode: ViewMode, 563 | dataProvider: vscode.TreeDataProvider 564 | ) { 565 | super('', collapsibleState); 566 | this.elementData = elementData; 567 | 568 | this.tooltip = elementData.info; 569 | this.command = { 570 | title: '', 571 | command: 'updateSelectedElement', 572 | arguments: [this], 573 | }; 574 | this.dataProvider = dataProvider; 575 | 576 | this.update(); 577 | } 578 | 579 | private update(): void { 580 | if (this.dataProvider.viewMode === ViewMode.standard) { 581 | this.label = this.elementData.groupedName; 582 | } 583 | if (this.dataProvider.viewMode === ViewMode.palette) { 584 | this.label = this.elementData.titleName; 585 | } 586 | this.colorConfig = this.dataProvider.colorConfigs[this.elementData.fullName]; 587 | const effectiveColor = getEffectiveColor(this.colorConfig); 588 | if (effectiveColor) { 589 | this.description = effectiveColor.toLowerCase(); 590 | } else { 591 | this.description = '-'; 592 | } 593 | this.iconPath = this.generateIcon(); 594 | } 595 | 596 | private generateIcon(): string { 597 | let iconPath = ''; 598 | let svgText = ''; 599 | 600 | let baseColor = ''; 601 | let topColor = ''; 602 | 603 | const colorConfig = this.colorConfig; 604 | 605 | // Decides the base color & top color, with only customizations appearing as topcoats 606 | 607 | if (colorConfig.settings.global && colorConfig.settings.workspace) { 608 | baseColor = colorConfig.settings.global; 609 | topColor = colorConfig.settings.workspace; 610 | } else { 611 | for (const item of [colorConfig.default, colorConfig.theme]) { 612 | if (item) { 613 | baseColor = item; 614 | } 615 | } 616 | for (const item of [colorConfig.settings.global, colorConfig.settings.workspace]) { 617 | if (item) { 618 | topColor = item; 619 | } 620 | } 621 | } 622 | 623 | // Load template svg text 624 | svgText = fs.readFileSync( 625 | path.join(__filename, '..', '..', 'resources', 'swatches', 'swatch.svg'), 626 | 'utf8' 627 | ); 628 | 629 | // Insert base color to svg text, change corresponding opacity to 1 from 0 630 | if (baseColor) { 631 | svgText = svgText.replace( 632 | 'fill:%COLOR1%;fill-opacity:0', 633 | 'fill:' + baseColor + ';fill-opacity:1' 634 | ); 635 | } 636 | 637 | // Insert top color to svg text,, change corresponding opacity to 1 from 0 638 | if (topColor) { 639 | svgText = svgText.replace( 640 | '