├── .github ├── CODEOWNERS ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md └── workflows │ ├── codeql-analysis.yml │ └── publish.yml ├── .gitignore ├── .prettierignore ├── .vscodeignore ├── LICENSE ├── README.md ├── default-dark.png ├── default-light.png ├── index.js ├── package.json ├── partial-dark.png ├── partial-light.png ├── samples ├── activity-calendar.js ├── activity-calendar.spec.ts ├── activity-calendar.ts ├── button.tsx ├── dark.css ├── light.css ├── smockle.css ├── smockle.html ├── smockle.scss └── smockle.tsx ├── templates ├── LICENSE ├── dark_plus.json ├── dark_vs.json ├── light_plus.json ├── light_vs.json ├── xcode-dark.json └── xcode-light.json ├── xcode-default-dark-theme.json ├── xcode-default-light-theme.json ├── xcode-partial-dark-theme.json └── xcode-partial-light-theme.json /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @smockle -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Report an issue with this project 4 | title: '' 5 | labels: bug 6 | assignees: smockle 7 | 8 | --- 9 | 10 | 11 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: enhancement 6 | assignees: smockle 7 | 8 | --- 9 | 10 | 11 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | name: "Code scanning - action" 2 | 3 | on: 4 | push: 5 | pull_request: 6 | schedule: 7 | - cron: '0 3 * * 1' 8 | 9 | jobs: 10 | CodeQL-Build: 11 | 12 | # CodeQL runs on ubuntu-latest and windows-latest 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - name: Checkout repository 17 | uses: actions/checkout@v2 18 | with: 19 | # We must fetch at least the immediate parents so that if this is 20 | # a pull request then we can checkout the head. 21 | fetch-depth: 2 22 | 23 | # If this run was triggered by a pull request event, then checkout 24 | # the head of the pull request instead of the merge commit. 25 | - run: git checkout HEAD^2 26 | if: ${{ github.event_name == 'pull_request' }} 27 | 28 | # Initializes the CodeQL tools for scanning. 29 | - name: Initialize CodeQL 30 | uses: github/codeql-action/init@v1 31 | # Override language selection by uncommenting this and choosing your languages 32 | # with: 33 | # languages: go, javascript, csharp, python, cpp, java 34 | 35 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 36 | # If this step fails, then you should remove it and run the build manually (see below) 37 | - name: Autobuild 38 | uses: github/codeql-action/autobuild@v1 39 | 40 | # ℹ️ Command-line programs to run using the OS shell. 41 | # 📚 https://git.io/JvXDl 42 | 43 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines 44 | # and modify them (or add more) to build your code if your project 45 | # uses a compiled language 46 | 47 | #- run: | 48 | # make bootstrap 49 | # make release 50 | 51 | - name: Perform CodeQL Analysis 52 | uses: github/codeql-action/analyze@v1 53 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish 2 | on: 3 | push: 4 | branches: ["main"] 5 | 6 | jobs: 7 | publish: 8 | name: Publish 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: Get sources 12 | if: contains(github.event.commits[0].message, '[skip ci]') == false 13 | uses: actions/checkout@v1 14 | with: 15 | fetch-depth: 1 16 | 17 | - name: Build 18 | if: contains(github.event.commits[0].message, '[skip ci]') == false 19 | uses: "lannonbr/vsce-action@75a30e358888a882724b568c7fcc80d7f087906c" 20 | with: 21 | args: "package" 22 | 23 | - name: Bump version 24 | if: contains(github.event.commits[0].message, '[skip ci]') == false 25 | uses: "smockle/action-version@main" 26 | env: 27 | GITHUB_USER_EMAIL: bot@smockle.com 28 | GITHUB_USER_NAME: smockle-bot 29 | GITHUB_ACCESS_TOKEN: ${{ secrets.GITHUB_ACCESS_TOKEN }} 30 | 31 | - name: Publish 32 | if: contains(github.event.commits[0].message, '[skip ci]') == false 33 | uses: "lannonbr/vsce-action@75a30e358888a882724b568c7fcc80d7f087906c" 34 | with: 35 | args: publish -p ${{ secrets.VSCE_ACCESS_TOKEN }} 36 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.vsix 2 | IsolatedStorage -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | package.json -------------------------------------------------------------------------------- /.vscodeignore: -------------------------------------------------------------------------------- 1 | .github 2 | samples 3 | templates 4 | default-dark.png 5 | default-light.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018-2019 Clay Miller 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Xcode Colors 2 | 3 | [![Visual Studio Marketplace](https://img.shields.io/vscode-marketplace/v/smockle.xcode-default-theme.svg)](https://marketplace.visualstudio.com/items?itemName=smockle.xcode-default-theme) 4 | 5 | Brings the colors of the Xcode 'Default (Dark)' and 'Default (Light)' themes to Visual Studio Code. 6 | 7 | ## Xcode Default 8 | 9 | Matches the default window and syntax colors of Xcode. 10 | 11 | ![Xcode Default (Dark) Screenshot](/default-dark.png?raw=true "Xcode Default (Dark) Screenshot") 12 | ![Xcode Default (Light) Screenshot](/default-light.png?raw=true "Xcode Default (Light) Screenshot") 13 | 14 | ## Xcode Partial 15 | 16 | Matches the default window colors of Xcode and the default syntax colors of Visual Studio Code (with adapted saturation). 17 | 18 | ![Xcode Partial (Dark) Screenshot](/partial-dark.png?raw=true "Xcode Partial (Dark) Screenshot") 19 | ![Xcode Partial (Light) Screenshot](/partial-light.png?raw=true "Xcode Partial (Light) Screenshot") 20 | 21 | # Recommended Settings 22 | 23 | For a more complete theme, add the following lines to your `settings.json`: 24 | 25 | ```JSON 26 | { 27 | "editor.cursorStyle": "line-thin", 28 | "editor.fontFamily": "'SF Mono', Menlo, Monaco, 'Courier New', monospace", 29 | "editor.fontLigatures": true, 30 | "editor.fontSize": 12, 31 | "editor.fontWeight": "500", 32 | "editor.lineHeight": 17, 33 | "terminal.integrated.fontSize": 12, 34 | "terminal.integrated.lineHeight": 1.23, 35 | "editor.minimap.enabled": false, 36 | "editor.minimap.renderCharacters": false, 37 | "editor.overviewRulerBorder": false, 38 | "editor.renderIndentGuides": false, 39 | "editor.renderLineHighlight": "all", 40 | "workbench.activityBar.visible": false, 41 | "workbench.editor.tabCloseButton": "left", 42 | "workbench.editor.showIcons": false, 43 | "window.nativeTabs": true, 44 | "editor.tokenColorCustomizations": { 45 | "[Xcode Partial (Light)]": { 46 | "textMateRules": [ 47 | { 48 | "scope": "comment", 49 | "settings": { 50 | "foreground": "#536579", 51 | "fontStyle": "italic" 52 | } 53 | } 54 | ] 55 | }, 56 | "[Xcode Partial (Dark)]": { 57 | "textMateRules": [ 58 | { 59 | "scope": "source", 60 | "settings": { 61 | "foreground": "#D4D4D4" 62 | } 63 | }, 64 | { 65 | "scope": "comment", 66 | "settings": { 67 | "foreground": "#6C7986", 68 | "fontStyle": "italic" 69 | } 70 | } 71 | ] 72 | } 73 | } 74 | } 75 | ``` 76 | -------------------------------------------------------------------------------- /default-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smockle-archive/xcode-default-theme/43784a0da4ee3647668fa7e7ca8eeea02daf9a66/default-dark.png -------------------------------------------------------------------------------- /default-light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smockle-archive/xcode-default-theme/43784a0da4ee3647668fa7e7ca8eeea02daf9a66/default-light.png -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | // @ts-check 3 | const fs = require("fs"); 4 | 5 | const colorMap = { 6 | dark: { 7 | "#d4d4d4": "#D4D4D4", 8 | "#000080": "#0000A6", 9 | "#6a9955": "#62AD41", 10 | "#569cd6": "#30A0FC", 11 | "#b5cea8": "#B1D99D", 12 | "#646695": "#5559A4", 13 | "#d7ba7d": "#F2C462", 14 | "#9cdcfe": "#7FE5FF", 15 | "#f44747": "#FF1313", 16 | "#ce9178": "#E8865E", 17 | "#6796e6": "#418CFF", 18 | "#808080": "#808080", 19 | "#d16969": "#F04A4A", 20 | "#dcdcaa": "#EBEB9B", 21 | "#4ec9b0": "#29EEC6", 22 | "#c586c0": "#D873D0" 23 | }, 24 | light: { 25 | "#000000ff": "#000000", 26 | "#000080": "#0A0A76", 27 | "#008000": "#0A760A", 28 | "#0000ff": "#1313EC", 29 | "#09885a": "#137E57", 30 | "#811f3f": "#7A2642", 31 | "#800000": "#760A0A", 32 | "#ff0000": "#EC1313", 33 | "#cd3131": "#C13D3D", 34 | "#a31515": "#982020", 35 | "#0451a5": "#105299", 36 | "#000000": "#000000", 37 | "#795e26": "#735C2C", 38 | "#267f99": "#2F7A90", 39 | "#af00db": "#A510CB", 40 | "#001080": "#0A1776", 41 | "#d16969": "#C97171" 42 | } 43 | }; 44 | 45 | function mapTokenColors(theme) { 46 | const themeVS = JSON.parse( 47 | fs.readFileSync(`./templates/${theme}_vs.json`, "utf8") 48 | ); 49 | const themePlus = JSON.parse( 50 | fs.readFileSync(`./templates/${theme}_plus.json`, "utf8") 51 | ); 52 | const tokenColors = [...themeVS.tokenColors, ...themePlus.tokenColors].map( 53 | tokenColor => { 54 | const mappedColor = { 55 | ...tokenColor 56 | }; 57 | if ( 58 | tokenColor.settings && 59 | tokenColor.settings.foreground && 60 | tokenColor.settings.foreground.toLowerCase() in colorMap[theme] 61 | ) { 62 | mappedColor.settings.foreground = 63 | colorMap[theme][tokenColor.settings.foreground.toLowerCase()]; 64 | } 65 | return mappedColor; 66 | } 67 | ); 68 | return tokenColors; 69 | } 70 | 71 | function writeTokenColors(theme) { 72 | const template = JSON.parse( 73 | fs.readFileSync(`./templates/xcode-${theme}.json`, "utf8") 74 | ); 75 | template.tokenColors = mapTokenColors(theme); 76 | fs.writeFileSync( 77 | `./xcode-partial-${theme}-theme.json`, 78 | JSON.stringify(template, null, 2) 79 | ); 80 | } 81 | 82 | writeTokenColors("dark"); 83 | writeTokenColors("light"); 84 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "xcode-default-theme", 3 | "displayName": "Xcode Default Theme", 4 | "description": "Brings the colors of the Xcode 'Default (Dark)' and 'Default (Light)' themes to Visual Studio Code", 5 | "categories": [ 6 | "Themes" 7 | ], 8 | "version": "2.0.23", 9 | "publisher": "smockle", 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/smockle/xcode-default-theme.git" 13 | }, 14 | "engines": { 15 | "vscode": "*" 16 | }, 17 | "contributes": { 18 | "themes": [ 19 | { 20 | "id": "Xcode Default (Dark)", 21 | "label": "Xcode Default (Dark)", 22 | "uiTheme": "vs-dark", 23 | "path": "./xcode-default-dark-theme.json" 24 | }, 25 | { 26 | "id": "Xcode Default (Light)", 27 | "label": "Xcode Default (Light)", 28 | "uiTheme": "vs", 29 | "path": "./xcode-default-light-theme.json" 30 | }, 31 | { 32 | "id": "Xcode Partial (Dark)", 33 | "label": "Xcode Partial (Dark)", 34 | "uiTheme": "vs-dark", 35 | "path": "./xcode-partial-dark-theme.json" 36 | }, 37 | { 38 | "id": "Xcode Partial (Light)", 39 | "label": "Xcode Partial (Light)", 40 | "uiTheme": "vs", 41 | "path": "./xcode-partial-light-theme.json" 42 | } 43 | ] 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /partial-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smockle-archive/xcode-default-theme/43784a0da4ee3647668fa7e7ca8eeea02daf9a66/partial-dark.png -------------------------------------------------------------------------------- /partial-light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smockle-archive/xcode-default-theme/43784a0da4ee3647668fa7e7ca8eeea02daf9a66/partial-light.png -------------------------------------------------------------------------------- /samples/activity-calendar.js: -------------------------------------------------------------------------------- 1 | import { round } from "lodash"; 2 | import { post } from "request-promise"; 3 | import { toMiles } from "../lib/to-miles.mjs"; 4 | import { load as dotenv } from "dotenv-safe"; 5 | dotenv(); 6 | export const handler = (event, context, callback) => { 7 | // Clean incoming data (from IFTTT) 8 | const body = JSON.parse(event.body); 9 | const { createdAt, distanceMeters, elapsedTimeInSeconds, name } = body; 10 | const distanceMiles = round(toMiles(parseFloat(distanceMeters)), 1); 11 | const elapsedTimeInMinutes = round(parseInt(elapsedTimeInSeconds, 10) / 60); 12 | // Prepare outgoing data 13 | const { IFTTT_EVENT, IFTTT_KEY } = process.env; 14 | const options = { 15 | method: "POST", 16 | uri: `https://maker.ifttt.com/trigger/${IFTTT_EVENT}/with/key/${IFTTT_KEY}`, 17 | body: { 18 | value1: `${name} (${distanceMiles} mi) ${createdAt} for ${elapsedTimeInMinutes} minutes` 19 | }, 20 | json: true 21 | }; 22 | // Send data to IFTTT 23 | const response = { 24 | statusCode: 200, 25 | body: JSON.stringify({ 26 | message: "Message sent!" 27 | }) 28 | }; 29 | post(options) 30 | .then(() => callback(null, response)) 31 | .catch(error => callback(error)); 32 | }; 33 | -------------------------------------------------------------------------------- /samples/activity-calendar.spec.ts: -------------------------------------------------------------------------------- 1 | jest.mock("request-promise"); 2 | jest.mock("dotenv-safe"); 3 | import { post } from "request-promise"; 4 | import { load as dotenv } from "dotenv-safe"; 5 | import { promisify } from "util"; 6 | import { 7 | handler as _handler, 8 | HandlerRequest, 9 | HandlerResponse 10 | } from "../src/bin/index.mjs"; 11 | const handler = promisify(_handler); 12 | dotenv(); 13 | 14 | describe("handler", () => { 15 | test("prepares outgoing data", () => { 16 | const event: HandlerRequest = { 17 | body: { 18 | createdAt: "March 17, 2018 at 02:00PM", 19 | name: "Afternoon Run", 20 | distanceMeters: "21375.5", 21 | elapsedTimeInSeconds: "7515" 22 | } 23 | }; 24 | const expected = { 25 | body: { 26 | value1: 27 | "Afternoon Run (13.3 mi) March 17, 2018 at 02:00PM for 125 minutes" 28 | }, 29 | json: true, 30 | method: "POST", 31 | uri: "https://maker.ifttt.com/trigger/IFTTT_EVENT/with/key/IFTTT_KEY" 32 | }; 33 | (post as any).mockResolvedValueOnce(); 34 | handler(event, null).then(() => { 35 | expect((post as any).mock.calls[0][0]).toEqual(expected); 36 | }); 37 | }); 38 | test("sends message successfully", () => { 39 | const event: HandlerRequest = { 40 | body: { 41 | createdAt: "March 17, 2018 at 02:00PM", 42 | name: "Afternoon Run", 43 | distanceMeters: "21375.5", 44 | elapsedTimeInSeconds: "7515" 45 | } 46 | }; 47 | const expected: HandlerResponse = { 48 | statusCode: 200, 49 | body: JSON.stringify({ 50 | message: "Message sent!" 51 | }) 52 | }; 53 | (post as any).mockResolvedValueOnce(); 54 | handler(event, null) 55 | .then((data: HandlerResponse | null) => { 56 | expect(data).toEqual(expected); 57 | }) 58 | .catch((error: Error | null) => { 59 | expect(error).toBeFalsy(); 60 | }); 61 | }); 62 | test("fails to send message", () => { 63 | const event: HandlerRequest = { 64 | body: { 65 | createdAt: "March 17, 2018 at 02:00PM", 66 | name: "Afternoon Run", 67 | distanceMeters: "21375.5", 68 | elapsedTimeInSeconds: "7515" 69 | } 70 | }; 71 | const expected = new Error("HI CLAY"); 72 | (post as any).mockRejectedValueOnce(expected); 73 | handler(event, null) 74 | .then((data: HandlerResponse | null) => { 75 | expect(data).toBeFalsy(); 76 | }) 77 | .catch((error: Error | null) => { 78 | expect(error).toEqual(expected); 79 | }); 80 | }); 81 | }); 82 | -------------------------------------------------------------------------------- /samples/activity-calendar.ts: -------------------------------------------------------------------------------- 1 | import { Handler, Context, Callback } from "aws-lambda"; 2 | import { round } from "lodash"; 3 | import { post } from "request-promise"; 4 | import { toMiles } from "../lib/to-miles.mjs"; 5 | import { load as dotenv } from "dotenv-safe"; 6 | dotenv(); 7 | 8 | export interface HandlerRequest { 9 | [key: string]: any; 10 | body: string; // HandlerRequestBody 11 | } 12 | 13 | export interface HandlerRequestBody { 14 | /** The activity start time, e.g "March 17, 2018 at 02:00PM" */ 15 | createdAt: string; 16 | /** The activity distance, in meters, e.g. "21375.5" */ 17 | distanceMeters: string; 18 | /** The activity duration, in seconds, e.g. "7515" */ 19 | elapsedTimeInSeconds: string; 20 | /** The activity name, e.g. "Afternoon Run" */ 21 | name: string; 22 | /** The activity type, e.g. "Run" */ 23 | activityType?: string; 24 | /** The activity duration, in hours, minutes and seconds, e.g. "2 hours, 5 minutes, 15 seconds" */ 25 | elapsedTime?: string; 26 | /** The activity URL on the Strava website, e.g. "http://www.strava.com/activities/1446540000" */ 27 | linkToActivity?: string; 28 | /** The activity route image URL on the Strava website */ 29 | routeMapImageURL?: string; 30 | [key: string]: any; 31 | } 32 | 33 | export interface HandlerResponse { 34 | statusCode: number; 35 | body: string; 36 | } 37 | 38 | export const handler: Handler = ( 39 | event: HandlerRequest, 40 | context: Context, 41 | callback: Callback 42 | ) => { 43 | // Clean incoming data (from IFTTT) 44 | const body: HandlerRequestBody = JSON.parse(event.body); 45 | const { createdAt, distanceMeters, elapsedTimeInSeconds, name } = body; 46 | const distanceMiles: number = round(toMiles(parseFloat(distanceMeters)), 1); 47 | const elapsedTimeInMinutes: number = round( 48 | parseInt(elapsedTimeInSeconds, 10) / 60 49 | ); 50 | // Prepare outgoing data 51 | const { IFTTT_EVENT, IFTTT_KEY } = process.env; 52 | const options = { 53 | method: "POST", 54 | uri: `https://maker.ifttt.com/trigger/${IFTTT_EVENT}/with/key/${IFTTT_KEY}`, 55 | body: { 56 | value1: `${name} (${distanceMiles} mi) ${createdAt} for ${elapsedTimeInMinutes} minutes` 57 | }, 58 | json: true 59 | }; 60 | // Send data to IFTTT 61 | const response: HandlerResponse = { 62 | statusCode: 200, 63 | body: JSON.stringify({ 64 | message: "Message sent!" 65 | }) 66 | }; 67 | post(options) 68 | .then(() => callback(null, response)) 69 | .catch(error => callback(error)); 70 | }; -------------------------------------------------------------------------------- /samples/button.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | @inject("foo") 4 | class Button extends React.Component { 5 | render() { 6 | const classNames = ["button"]; 7 | return