├── .appcast.xml
├── .gitignore
├── LICENSE
├── README.md
├── assets
└── icon.png
├── colors
├── ant-design.txt
├── atlassian-design.txt
└── material-design.txt
├── package-lock.json
├── package.json
├── src
├── export.js
├── import.js
├── lib
│ ├── aco-to-colors.js
│ ├── act-to-colors.js
│ ├── ase-to-colors.js
│ ├── clr-to-colors.js
│ ├── color.js
│ ├── gpl-to-colors.js
│ ├── is-json-string.js
│ ├── is-zip.js
│ ├── sketch-to-colors.js
│ ├── sketchpalette-to-colors.js
│ ├── sketchpreset-to-colors.js
│ └── txt-to-colors.js
└── manifest.json
└── webpack.skpm.config.js
/.appcast.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | -
5 |
6 |
7 | -
8 |
9 |
10 | -
11 |
12 |
13 | -
14 |
15 |
16 | -
17 |
18 |
19 | -
20 |
21 |
22 | -
23 |
24 |
25 | -
26 |
27 |
28 | -
29 |
30 |
31 | -
32 |
33 |
34 | -
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # build artifacts
2 | import-colors.sketchplugin
3 |
4 | # npm
5 | node_modules
6 | .npm
7 | npm-debug.log
8 |
9 | # mac
10 | .DS_Store
11 |
12 | # WebStorm
13 | .idea
14 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Ashung Hung
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 | # Import Colors
2 |
3 | Import colors from swatches file to Sketch. **(For Sketch 53+)**
4 |
5 | ## Installation
6 |
7 | - [Download](https://github.com/Ashung/import-colors-sketch/releases/latest/download/import-colors.sketchplugin.zip) zip file, unzip and double click on the ".sketchplugin" file.
8 | - Search "import colors" from [Sketch Runner](http://sketchrunner.com/).
9 |
10 | ## Features
11 |
12 | ### V1.0.x (for Sketch 53 ~ 68.x)
13 |
14 | - Import Colors to Document / Global
15 | - Import Colors as Library
16 | - Export Document / Global Colors to .txt or .clr file
17 | - Convert Colors to .txt or .clr File
18 | - Reset Global Colors
19 |
20 | ### V2.0.x (for Sketch 69+)
21 |
22 | - Import Colors to Color Variables
23 | - Import Colors as Library
24 | - Import Colors and Update Color Variables
25 | - Convert Color Variables to .txt or .clr File
26 | - Export Color Variables to .txt or .clr file
27 |
28 | ## Supported Formats
29 |
30 | | Name | Extension | Support Application |
31 | | -------------------------- | ---------------- | ----------------------------------- |
32 | | Apple Color Picker Palette | `.clr` | macOS Color Picker 1 |
33 | | Adobe Color Swatch | `.aco` | Photoshop 2 |
34 | | Adobe Color Table | `.act` | Photoshop 2 |
35 | | Adobe Swatch Exchange | `.ase` | Photoshop, Illustrator 2 |
36 | | GIMP Palette | `.gpl` | GIMP, Inkscape |
37 | | Sketch Palette | `.sketchpalette` | Sketch (old version) |
38 | | Sketch Preset | `.sketchpreset` | Sketch 3 |
39 | | Sketch Document | `.sketch` | Sketch 3 |
40 | | Text File | `.txt`, `.text` | Text Editor 4 |
41 |
42 | 1. In Sketch run "View" - "Show Colors", select palette tab, then click the gear icon, to open .clr files.
43 | 2. The color save in CMYK, LAB, Grayscale model from .aco or .ase file, maybe have different hex value between Sketch and Photoshop.
44 | 3. Only import document colors.
45 | 4. Save colors in each lines, like `red: #ff0000`, color support hex, CSS color name, 8-digit hex, rgb, rgba, hsl, hsla.
46 |
47 | ## License
48 |
49 | MIT
50 |
51 | ## Donate
52 |
53 | [Buy me a coffee](https://www.buymeacoffee.com/ashung) or donate [$2.00](https://www.paypal.me/ashung/2) [$5.00](https://www.paypal.me/ashung/5) [$10.00](https://www.paypal.me/ashung/10) via PayPal.
54 |
55 | -----
56 |
57 | > **NOTE**
58 | > _This plugin was created using `skpm`. For a detailed explanation on how things work, checkout the [skpm Readme](https://github.com/skpm/skpm/blob/master/README.md)._
59 |
--------------------------------------------------------------------------------
/assets/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Ashung/import-colors-sketch/733f1bb8519cb01139c742d6cb0d4b26ee40c656/assets/icon.png
--------------------------------------------------------------------------------
/colors/ant-design.txt:
--------------------------------------------------------------------------------
1 | red-1: #fff1f0
2 | red-2: #ffccc7
3 | red-3: #ffa39e
4 | red-4: #ff7875
5 | red-5: #ff4d4f
6 | red-6: #f5222d
7 | red-7: #cf1322
8 | red-8: #a8071a
9 | red-9: #820014
10 | red-10: #5c0011
11 | volcano-1: #fff2e8
12 | volcano-2: #ffd8bf
13 | volcano-3: #ffbb96
14 | volcano-4: #ff9c6e
15 | volcano-5: #ff7a45
16 | volcano-6: #fa541c
17 | volcano-7: #d4380d
18 | volcano-8: #ad2102
19 | volcano-9: #871400
20 | volcano-10: #610b00
21 | orange-1: #fff7e6
22 | orange-2: #ffe7ba
23 | orange-3: #ffd591
24 | orange-4: #ffc069
25 | orange-5: #ffa940
26 | orange-6: #fa8c16
27 | orange-7: #d46b08
28 | orange-8: #ad4e00
29 | orange-9: #873800
30 | orange-10: #612500
31 | gold-1: #fffbe6
32 | gold-2: #fff1b8
33 | gold-3: #ffe58f
34 | gold-4: #ffd666
35 | gold-5: #ffc53d
36 | gold-6: #faad14
37 | gold-7: #d48806
38 | gold-8: #ad6800
39 | gold-9: #874d00
40 | gold-10: #613400
41 | yellow-1: #feffe6
42 | yellow-2: #ffffb8
43 | yellow-3: #fffb8f
44 | yellow-4: #fff566
45 | yellow-5: #ffec3d
46 | yellow-6: #fadb14
47 | yellow-7: #d4b106
48 | yellow-8: #ad8b00
49 | yellow-9: #876800
50 | yellow-10: #614700
51 | lime-1: #fcffe6
52 | lime-2: #f4ffb8
53 | lime-3: #eaff8f
54 | lime-4: #d3f261
55 | lime-5: #bae637
56 | lime-6: #a0d911
57 | lime-7: #7cb305
58 | lime-8: #5b8c00
59 | lime-9: #3f6600
60 | lime-10: #254000
61 | green-1: #f6ffed
62 | green-2: #d9f7be
63 | green-3: #b7eb8f
64 | green-4: #95de64
65 | green-5: #73d13d
66 | green-6: #52c41a
67 | green-7: #389e0d
68 | green-8: #237804
69 | green-9: #135200
70 | green-10: #092b00
71 | cyan-1: #e6fffb
72 | cyan-2: #b5f5ec
73 | cyan-3: #87e8de
74 | cyan-4: #5cdbd3
75 | cyan-5: #36cfc9
76 | cyan-6: #13c2c2
77 | cyan-7: #08979c
78 | cyan-8: #006d75
79 | cyan-9: #00474f
80 | cyan-10: #002329
81 | blue-1: #e6f7ff
82 | blue-2: #bae7ff
83 | blue-3: #91d5ff
84 | blue-4: #69c0ff
85 | blue-5: #40a9ff
86 | blue-6: #1890ff
87 | blue-7: #096dd9
88 | blue-8: #0050b3
89 | blue-9: #003a8c
90 | blue-10: #002766
91 | geekblue-1: #f0f5ff
92 | geekblue-2: #d6e4ff
93 | geekblue-3: #adc6ff
94 | geekblue-4: #85a5ff
95 | geekblue-5: #597ef7
96 | geekblue-6: #2f54eb
97 | geekblue-7: #1d39c4
98 | geekblue-8: #10239e
99 | geekblue-9: #061178
100 | geekblue-10: #030852
101 | purple-1: #f9f0ff
102 | purple-2: #efdbff
103 | purple-3: #d3adf7
104 | purple-4: #b37feb
105 | purple-5: #9254de
106 | purple-6: #722ed1
107 | purple-7: #531dab
108 | purple-8: #391085
109 | purple-9: #22075e
110 | purple-10: #120338
111 | magenta-1: #fff0f6
112 | magenta-2: #ffd6e7
113 | magenta-3: #ffadd2
114 | magenta-4: #ff85c0
115 | magenta-5: #f759ab
116 | magenta-6: #eb2f96
117 | magenta-7: #c41d7f
118 | magenta-8: #9e1068
119 | magenta-9: #780650
120 | magenta-10: #520339
--------------------------------------------------------------------------------
/colors/atlassian-design.txt:
--------------------------------------------------------------------------------
1 | R500 - Dragon's blood: #BF2600
2 | R400 - Red dirt: #DE350B
3 | R300 - Poppy surprise: #FF5630
4 | R200 - Salmon sashimi: #FF7452
5 | R100 - Alexandria: #FF8F73
6 | R75 - Bondi sunburn: #FFBDAD
7 | R50 - Rosie: #FFEBE6
8 | Y500 - Debrito: #FF8B00
9 | Y400 - Cheezy blasters: #FF991F
10 | Y300 - Golden state: #FFAB00
11 | Y200 - Pub mix: #FFC400
12 | Y100 - Cowbell: #FFE380
13 | Y75 - Dandelion whisper: #FFF0B3
14 | Y50 - James blonde: #FFFAE6
15 | G500 - Keen green: #006644
16 | G400 - Slime: #00875A
17 | G300 - Fine pine: #36B37E
18 | G200 - Green tea: #57D9A3
19 | G100 - Cloverleaf: #79F2C0
20 | G75 - Mintie: #ABF5D1
21 | G50 - The smell: #E3FCEF
22 | T500 - Shabby chic: #008DA6
23 | T400 - Prom dress: #00A3BF
24 | T300 - Tamarama: #00B8D9
25 | T200 - Mermaid net: #00C7E6
26 | T100 - Hairy fairy: #79E2F2
27 | T75 - Arctic chill: #B3F5FF
28 | T50 - Gram's sofa: #E6FCFF
29 | B500 - Chore coat: #0747A6
30 | B400 - Pacific bridge: #0052CC
31 | B300 - Sodium explosion: #0065FF
32 | B200 - Coogee: #2684FF
33 | B100 - Arvo breeze: #4C9AFF
34 | B75 - Schwag: #B3D4FF
35 | B50 - Pixie dust: #DEEBFF
36 | P500 - Prince: #403294
37 | P400 - Snozzberry: #5243AA
38 | P300 - Da' juice: #6554C0
39 | P200 - Pastelli: #8777D9
40 | P100 - Herky jerky: #998DD9
41 | P75 - Phantom mist: #C0B6F2
42 | P50 - Lavender secret: #EAE6FF
43 | N900 - Slate: #091E42
44 | N800 - Squid ink: #172B4D
45 | N700 - Snorlax: #253858
46 | N600 - Pet rock: #344563
47 | N500 - McFanning: #42526E
48 | N400 - Concrete jungle: #505F79
49 | N300 - Clooney: #5E6C84
50 | N200 - Bling bling: #6B778C
51 | N100 - Humboldt fog: #7A869A
52 | N90 - Meredith: #8993A4
53 | N80 - Spooky ghost: #97A0AF
54 | N70 - Blanche: #A5ADBA
55 | N60 - Sentinel: #B3BAC5
56 | N50 - Karl: #C1C7D0
57 | N40 - Jolly fun time: #DFE1E6
58 | N30 - Northeast snow: #EBECF0
59 | N20 - Gram's hair: #F4F5F7
60 | N10 - Wash me: #FAFBFC
61 | N0 - Doctor: #FFFFFF
--------------------------------------------------------------------------------
/colors/material-design.txt:
--------------------------------------------------------------------------------
1 | Red 50: #FFEBEE
2 | Red 100: #FFCDD2
3 | Red 200: #EF9A9A
4 | Red 300: #E57373
5 | Red 400: #EF5350
6 | Red 500: #F44336
7 | Red 600: #E53935
8 | Red 700: #D32F2F
9 | Red 800: #C62828
10 | Red 900: #B71C1C
11 | Red A100: #FF8A80
12 | Red A200: #FF5252
13 | Red A400: #FF1744
14 | Red A700: #D50000
15 | Pink 50: #FCE4EC
16 | Pink 100: #F8BBD0
17 | Pink 200: #F48FB1
18 | Pink 300: #F06292
19 | Pink 400: #EC407A
20 | Pink 500: #E91E63
21 | Pink 600: #D81B60
22 | Pink 700: #C2185B
23 | Pink 800: #AD1457
24 | Pink 900: #880E4F
25 | Pink A100: #FF80AB
26 | Pink A200: #FF4081
27 | Pink A400: #F50057
28 | Pink A700: #C51162
29 | Purple 50: #F3E5F5
30 | Purple 100: #E1BEE7
31 | Purple 200: #CE93D8
32 | Purple 300: #BA68C8
33 | Purple 400: #AB47BC
34 | Purple 500: #9C27B0
35 | Purple 600: #8E24AA
36 | Purple 700: #7B1FA2
37 | Purple 800: #6A1B9A
38 | Purple 900: #4A148C
39 | Purple A100: #EA80FC
40 | Purple A200: #E040FB
41 | Purple A400: #D500F9
42 | Purple A700: #AA00FF
43 | Deep purple 50: #EDE7F6
44 | Deep purple 100: #D1C4E9
45 | Deep purple 200: #B39DDB
46 | Deep purple 300: #9575CD
47 | Deep purple 400: #7E57C2
48 | Deep purple 500: #673AB7
49 | Deep purple 600: #5E35B1
50 | Deep purple 700: #512DA8
51 | Deep purple 800: #4527A0
52 | Deep purple 900: #311B92
53 | Deep purple A100: #B388FF
54 | Deep purple A200: #7C4DFF
55 | Deep purple A400: #651FFF
56 | Deep purple A700: #6200EA
57 | Indigo 50: #E8EAF6
58 | Indigo 100: #C5CAE9
59 | Indigo 200: #9FA8DA
60 | Indigo 300: #7986CB
61 | Indigo 400: #5C6BC0
62 | Indigo 500: #3F51B5
63 | Indigo 600: #3949AB
64 | Indigo 700: #303F9F
65 | Indigo 800: #283593
66 | Indigo 900: #1A237E
67 | Indigo A100: #8C9EFF
68 | Indigo A200: #536DFE
69 | Indigo A400: #3D5AFE
70 | Indigo A700: #304FFE
71 | Blue 50: #E3F2FD
72 | Blue 100: #BBDEFB
73 | Blue 200: #90CAF9
74 | Blue 300: #64B5F6
75 | Blue 400: #42A5F5
76 | Blue 500: #2196F3
77 | Blue 600: #1E88E5
78 | Blue 700: #1976D2
79 | Blue 800: #1565C0
80 | Blue 900: #0D47A1
81 | Blue A100: #82B1FF
82 | Blue A200: #448AFF
83 | Blue A400: #2979FF
84 | Blue A700: #2962FF
85 | Light Blue 50: #E1F5FE
86 | Light Blue 100: #B3E5FC
87 | Light Blue 200: #81D4FA
88 | Light Blue 300: #4FC3F7
89 | Light Blue 400: #29B6F6
90 | Light Blue 500: #03A9F4
91 | Light Blue 600: #039BE5
92 | Light Blue 700: #0288D1
93 | Light Blue 800: #0277BD
94 | Light Blue 900: #01579B
95 | Light Blue A100: #80D8FF
96 | Light Blue A200: #40C4FF
97 | Light Blue A400: #00B0FF
98 | Light Blue A700: #0091EA
99 | Cyan 50: #E0F7FA
100 | Cyan 100: #B2EBF2
101 | Cyan 200: #80DEEA
102 | Cyan 300: #4DD0E1
103 | Cyan 400: #26C6DA
104 | Cyan 500: #00BCD4
105 | Cyan 600: #00ACC1
106 | Cyan 700: #0097A7
107 | Cyan 800: #00838F
108 | Cyan 900: #006064
109 | Cyan A100: #84FFFF
110 | Cyan A200: #18FFFF
111 | Cyan A400: #00E5FF
112 | Cyan A700: #00B8D4
113 | Teal 50: #E0F2F1
114 | Teal 100: #B2DFDB
115 | Teal 200: #80CBC4
116 | Teal 300: #4DB6AC
117 | Teal 400: #26A69A
118 | Teal 500: #009688
119 | Teal 600: #00897B
120 | Teal 700: #00796B
121 | Teal 800: #00695C
122 | Teal 900: #004D40
123 | Teal A100: #A7FFEB
124 | Teal A200: #64FFDA
125 | Teal A400: #1DE9B6
126 | Teal A700: #00BFA5
127 | Green 50: #E8F5E9
128 | Green 100: #C8E6C9
129 | Green 200: #A5D6A7
130 | Green 300: #81C784
131 | Green 400: #66BB6A
132 | Green 500: #4CAF50
133 | Green 600: #43A047
134 | Green 700: #388E3C
135 | Green 800: #2E7D32
136 | Green 900: #1B5E20
137 | Green A100: #B9F6CA
138 | Green A200: #69F0AE
139 | Green A400: #00E676
140 | Green A700: #00C853
141 | Light Green 50: #F1F8E9
142 | Light Green 100: #DCEDC8
143 | Light Green 200: #C5E1A5
144 | Light Green 300: #AED581
145 | Light Green 400: #9CCC65
146 | Light Green 500: #8BC34A
147 | Light Green 600: #7CB342
148 | Light Green 700: #689F38
149 | Light Green 800: #558B2F
150 | Light Green 900: #33691E
151 | Light Green A100: #CCFF90
152 | Light Green A200: #B2FF59
153 | Light Green A400: #76FF03
154 | Light Green A700: #64DD17
155 | Lime 50: #F9FBE7
156 | Lime 100: #F0F4C3
157 | Lime 200: #E6EE9C
158 | Lime 300: #DCE775
159 | Lime 400: #D4E157
160 | Lime 500: #CDDC39
161 | Lime 600: #C0CA33
162 | Lime 700: #AFB42B
163 | Lime 800: #9E9D24
164 | Lime 900: #827717
165 | Lime A100: #F4FF81
166 | Lime A200: #EEFF41
167 | Lime A400: #C6FF00
168 | Lime A700: #AEEA00
169 | Yellow 50: #FFFDE7
170 | Yellow 100: #FFF9C4
171 | Yellow 200: #FFF59D
172 | Yellow 300: #FFF176
173 | Yellow 400: #FFEE58
174 | Yellow 500: #FFEB3B
175 | Yellow 600: #FDD835
176 | Yellow 700: #FBC02D
177 | Yellow 800: #F9A825
178 | Yellow 900: #F57F17
179 | Yellow A100: #FFFF8D
180 | Yellow A200: #FFFF00
181 | Yellow A400: #FFEA00
182 | Yellow A700: #FFD600
183 | Amber 50: #FFF8E1
184 | Amber 100: #FFECB3
185 | Amber 200: #FFE082
186 | Amber 300: #FFD54F
187 | Amber 400: #FFCA28
188 | Amber 500: #FFC107
189 | Amber 600: #FFB300
190 | Amber 700: #FFA000
191 | Amber 800: #FF8F00
192 | Amber 900: #FF6F00
193 | Amber A100: #FFE57F
194 | Amber A200: #FFD740
195 | Amber A400: #FFC400
196 | Amber A700: #FFAB00
197 | Orange 50: #FFF3E0
198 | Orange 100: #FFE0B2
199 | Orange 200: #FFCC80
200 | Orange 300: #FFB74D
201 | Orange 400: #FFA726
202 | Orange 500: #FF9800
203 | Orange 600: #FB8C00
204 | Orange 700: #F57C00
205 | Orange 800: #EF6C00
206 | Orange 900: #E65100
207 | Orange A100: #FFD180
208 | Orange A200: #FFAB40
209 | Orange A400: #FF9100
210 | Orange A700: #FF6D00
211 | Deep Orange 50: #FBE9E7
212 | Deep Orange 100: #FFCCBC
213 | Deep Orange 200: #FFAB91
214 | Deep Orange 300: #FF8A65
215 | Deep Orange 400: #FF7043
216 | Deep Orange 500: #FF5722
217 | Deep Orange 600: #F4511E
218 | Deep Orange 700: #E64A19
219 | Deep Orange 800: #D84315
220 | Deep Orange 900: #BF360C
221 | Deep Orange A100: #FF9E80
222 | Deep Orange A200: #FF6E40
223 | Deep Orange A400: #FF3D00
224 | Deep Orange A700: #DD2C00
225 | Brown 50: #EFEBE9
226 | Brown 100: #D7CCC8
227 | Brown 200: #BCAAA4
228 | Brown 300: #A1887F
229 | Brown 400: #8D6E63
230 | Brown 500: #795548
231 | Brown 600: #6D4C41
232 | Brown 700: #5D4037
233 | Brown 800: #4E342E
234 | Brown 900: #3E2723
235 | Gray 50: #FAFAFA
236 | Gray 100: #F5F5F5
237 | Gray 200: #EEEEEE
238 | Gray 300: #E0E0E0
239 | Gray 400: #BDBDBD
240 | Gray 500: #9E9E9E
241 | Gray 600: #757575
242 | Gray 700: #616161
243 | Gray 800: #424242
244 | Gray 900: #212121
245 | Blue Gray 50: #ECEFF1
246 | Blue Gray 100: #CFD8DC
247 | Blue Gray 200: #B0BEC5
248 | Blue Gray 300: #90A4AE
249 | Blue Gray 400: #78909C
250 | Blue Gray 500: #607D8B
251 | Blue Gray 600: #546E7A
252 | Blue Gray 700: #455A64
253 | Blue Gray 800: #37474F
254 | Blue Gray 900: #263238
255 | Black: #000000
256 | White: #FFFFFF
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "import-colors",
3 | "version": "2.0.3",
4 | "description": "Import colors from swatches file to Sketch. (For Sketch 69+)",
5 | "engines": {
6 | "sketch": ">=3.0"
7 | },
8 | "skpm": {
9 | "name": "import-colors",
10 | "manifest": "src/manifest.json",
11 | "main": "import-colors.sketchplugin",
12 | "assets": [
13 | "assets/**/*"
14 | ]
15 | },
16 | "scripts": {
17 | "build": "export NODE_OPTIONS=--openssl-legacy-provider && skpm-build",
18 | "watch": "export NODE_OPTIONS=--openssl-legacy-provider && skpm-build --watch",
19 | "start": "export NODE_OPTIONS=--openssl-legacy-provider && skpm-build --watch --run",
20 | "postinstall": "export NODE_OPTIONS=--openssl-legacy-provider && npm run build && skpm-link"
21 | },
22 | "repository": {
23 | "type": "git",
24 | "url": "git+https://github.com/Ashung/import-colors-sketch.git"
25 | },
26 | "author": "Ashung ",
27 | "license": "MIT",
28 | "dependencies": {
29 | "@skpm/dialog": "^0.2.6",
30 | "@skpm/fs": "^0.2.6"
31 | },
32 | "devDependencies": {
33 | "@skpm/builder": "^0.7.7"
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/export.js:
--------------------------------------------------------------------------------
1 | import { UI } from 'sketch';
2 | import sketch from 'sketch/dom';
3 | import { Swatch } from 'sketch/dom';
4 | import dialog from '@skpm/dialog';
5 | import { writeFileSync } from '@skpm/fs';
6 | import color from './lib/color';
7 | import { toArray } from 'util';
8 | import { extname } from 'path';
9 |
10 | export default function(context) {
11 |
12 | const document = sketch.getSelectedDocument();
13 | const identifier = String(__command.identifier());
14 |
15 | let colors;
16 | dialog.showMessageBox(
17 | {
18 | type: 'none',
19 | buttons: ['OK', 'Cancel'],
20 | message: 'Export colors',
21 | checkboxLabel: 'Include color variables from library.',
22 | checkboxChecked: false
23 | },
24 | ({ response, checkboxChecked }) => {
25 | if (response === 0) {
26 | if (checkboxChecked) {
27 | colors = toArray(document._getMSDocumentData().allSwatches()).map(swatch => {
28 | return Swatch.fromNative(swatch);
29 | });
30 | } else {
31 | colors = document.swatches;
32 | }
33 | } else {
34 | return;
35 | }
36 | }
37 | );
38 |
39 | if (colors.length === 0) {
40 | UI.message('Document have no color variables.');
41 | return;
42 | }
43 |
44 | let filter;
45 | if (identifier === 'export-color-variables-to-clr-file') {
46 | filter = { name: 'Apple Color Picker Palette', extensions: [ 'clr' ] }
47 | }
48 | if (identifier === 'export-color-variables-to-txt-file') {
49 | filter = { name: 'Text File', extensions: [ 'txt', 'text' ] }
50 | }
51 |
52 | dialog.showSaveDialog(
53 | {
54 | filters: [filter]
55 | },
56 | (filePath) => {
57 | if (identifier === 'export-color-variables-to-clr-file') {
58 | if (extname(filePath) === '') {
59 | filePath += '.clr';
60 | }
61 | let colorList = color.colorListFromArray(colors);
62 | colorList.writeToFile(filePath);
63 | }
64 | if (identifier === 'export-color-variables-to-txt-file') {
65 | if (extname(filePath) === '') {
66 | filePath += '.txt';
67 | }
68 | let keyCount = {};
69 | let text = color.toTextContent(colors, keyCount);
70 | writeFileSync(filePath, text);
71 | }
72 | UI.message('Colors save to "' + filePath + '".');
73 | }
74 | );
75 |
76 | }
--------------------------------------------------------------------------------
/src/import.js:
--------------------------------------------------------------------------------
1 | import { UI } from 'sketch';
2 | import { Document, Artboard, ShapePath, Rectangle, Library, Style, Swatch } from 'sketch/dom';
3 | import sketch from 'sketch/dom';
4 | import { extname, basename } from 'path';
5 | import os from 'os';
6 | import dialog from '@skpm/dialog';
7 | import { existsSync, mkdirSync, readdirSync, unlinkSync, writeFileSync } from '@skpm/fs';
8 | import color from './lib/color';
9 | import clr2colors from './lib/clr-to-colors';
10 | import gpl2colors from './lib/gpl-to-colors';
11 | import aco2colors from './lib/aco-to-colors';
12 | import act2colors from './lib/act-to-colors';
13 | import ase2colors from './lib/ase-to-colors';
14 | import sketchpreset2colors from './lib/sketchpreset-to-colors';
15 | import sketchpalette2colors from './lib/sketchpalette-to-colors';
16 | import sketch2colors from './lib/sketch-to-colors';
17 | import txt2colors from './lib/txt-to-colors';
18 |
19 | export default function(context) {
20 |
21 | const identifier = String(__command.identifier());
22 |
23 | dialog.showOpenDialog({
24 | filters: [
25 | { name: 'Apple Color Picker Palette', extensions: [ 'clr' ] },
26 | { name: 'Adobe Color Swatch', extensions: [ 'aco' ] },
27 | { name: 'Adobe Color Table', extensions: [ 'act' ] },
28 | { name: 'Adobe Swatch Exchange', extensions: [ 'ase' ] },
29 | { name: 'GIMP Palette', extensions: [ 'gpl' ] },
30 | { name: 'Sketch', extensions: [ 'sketchpreset', 'sketchpalette', 'sketch' ] },
31 | { name: 'Text File', extensions: [ 'txt', 'text' ] }
32 | ],
33 | properties: [ 'openFile' ]
34 | }, (filePaths) => {
35 |
36 | let colors;
37 | let filePath = filePaths[0];
38 | let fileName = basename(filePath);
39 | let fileType = extname(filePath).toLowerCase();
40 | if (fileType === '.clr') {
41 | colors = clr2colors(filePath);
42 | } else if (fileType === '.aco') {
43 | colors = aco2colors(filePath);
44 | } else if (fileType === '.act') {
45 | colors = act2colors(filePath);
46 | } else if (fileType === '.ase') {
47 | colors = ase2colors(filePath);
48 | } else if (fileType === '.gpl') {
49 | colors = gpl2colors(filePath);
50 | } else if (fileType === '.sketchpreset') {
51 | colors = sketchpreset2colors(filePath);
52 | } else if (fileType === '.sketchpalette') {
53 | colors = sketchpalette2colors(filePath);
54 | } else if (fileType === '.sketch') {
55 | if (sketch.getSelectedDocument().path === filePath) {
56 | UI.message('The sketch file is current document.');
57 | return;
58 | }
59 | colors = sketch2colors(filePath);
60 | } else if (fileType === '.txt' || fileType === '.text') {
61 | colors = txt2colors(filePath);
62 | } else {
63 | UI.message('Unknown file format.');
64 | }
65 |
66 | if (colors === undefined) {
67 | return;
68 | }
69 |
70 | if (Array.isArray(colors) && colors.length === 0) {
71 | UI.message('No colors.');
72 | return;
73 | }
74 |
75 | if (identifier === 'import-colors-to-color-variables') {
76 |
77 | let document = sketch.getSelectedDocument();
78 | let swatches = document.swatches;
79 | if (swatches.length === 0) {
80 | dialog.showMessageBox(
81 | {
82 | type: 'none',
83 | buttons: ['OK', 'Cancel'],
84 | message: 'Import colors from "' + fileName + '"?',
85 | checkboxLabel: 'Auto add numbers in front of Color Variables.',
86 | checkboxChecked: true
87 | },
88 | ({ response, checkboxChecked }) => {
89 | if (response === 0) {
90 | addColorVariables(checkboxChecked);
91 | } else {
92 | return;
93 | }
94 | }
95 | );
96 | } else {
97 | dialog.showMessageBox(
98 | {
99 | type: 'none',
100 | buttons: ['OK', 'Cancel', 'Append'],
101 | message: 'Remove all existing color variables, before import colors from "' + fileName + '"?',
102 | checkboxLabel: 'Auto add numbers in front of Color Variables.',
103 | checkboxChecked: true
104 | },
105 | ({ response, checkboxChecked }) => {
106 | if (response === 0) {
107 | removeAllColorVariables();
108 | addColorVariables(checkboxChecked);
109 | } else if (response === 1) {
110 | return;
111 | } else if (response === 2) {
112 | addColorVariables(checkboxChecked);
113 | }
114 | }
115 | );
116 | }
117 |
118 | function removeAllColorVariables() {
119 | document.swatches = [];
120 | }
121 |
122 | function addColorVariables(addNumber) {
123 | colors.forEach((item, index) => {
124 | let name = item.name;
125 | if (addNumber) {
126 | name = item.name.replace(/\/([^\/]*)$/, `/${index + 1}. $1`);
127 | }
128 | const swatch = Swatch.from({
129 | name,
130 | color: item.color
131 | });
132 | swatches.push(swatch);
133 | });
134 | UI.message(`Import ${colors.length} color variable${colors.length > 1 ? 's' : ''} to document.`);
135 | }
136 |
137 | }
138 |
139 | else if (identifier === 'convert-colors-to-clr-file') {
140 | dialog.showSaveDialog(
141 | {
142 | filters: [
143 | { name: 'Apple Color Picker Palette', extensions: [ 'clr' ] }
144 | ]
145 | },
146 | (filePath) => {
147 | let colorList = color.colorListFromArray(colors);
148 | colorList.writeToFile(filePath);
149 | UI.message('Colors have convert to .clr file.');
150 | }
151 | );
152 | }
153 |
154 | else if (identifier === 'convert-colors-to-txt-file') {
155 | dialog.showSaveDialog(
156 | {
157 | filters: [
158 | { name: 'Text File', extensions: [ 'txt', 'text' ] }
159 | ]
160 | },
161 | (filePath) => {
162 | let keyCount = {};
163 | let text = color.toTextContent(colors, keyCount);
164 | writeFileSync(filePath, text);
165 | UI.message('Colors have convert to .txt file.');
166 | }
167 | );
168 | }
169 |
170 | else if (identifier === 'import-colors-as-library') {
171 |
172 | dialog.showMessageBox(
173 | {
174 | type: 'none',
175 | buttons: ['OK', 'Cancel'],
176 | message: 'Import colors as library from "' + fileName + '"?',
177 | checkboxLabel: 'Auto add numbers in front of Color Variables.',
178 | checkboxChecked: true
179 | },
180 | ({ response, checkboxChecked }) => {
181 | if (response === 1) {
182 | return;
183 | } else {
184 |
185 | let libraryFolder = os.homedir() + '/Library/Application Support/com.bohemiancoding.sketch3/Plugins/import-colors-libraries/';
186 | let libraryPath = libraryFolder + fileName.replace(/\.\w+$/i, '.sketch');
187 |
188 | if (!existsSync(libraryFolder)) {
189 | mkdirSync(libraryFolder);
190 | }
191 |
192 | let msDocument = MSDocument.alloc().init();
193 | let document = Document.fromNative(msDocument);
194 |
195 | // Page
196 | document.pages[0].name = 'Library Preview';
197 |
198 | // Add artboard
199 | let artboard = new Artboard({
200 | name: 'Library Preview',
201 | parent: document.pages[0],
202 | frame: new Rectangle(0, 0, 400, 400)
203 | });
204 |
205 | colors.forEach((item, index) => {
206 |
207 | // Add colors
208 | const colorName = (checkboxChecked ? `${index + 1}. ` : '') + item.name;
209 | const swatch = Swatch.from({
210 | name: colorName,
211 | color: item.color
212 | });
213 | document.swatches.push(swatch);
214 |
215 | // Add layers 4 x 4
216 | if (index < 16) {
217 | let x = (index % 4) * 90 + 40;
218 | let y = Math.floor(index / 4) * 90 + 40;
219 | const layer = new ShapePath({
220 | name: colorName,
221 | parent: artboard,
222 | shapeType: ShapePath.ShapeType.Oval,
223 | frame: new Rectangle(x, y, 50, 50),
224 | style: {
225 | fills: [
226 | {
227 | color: swatch.referencingColor
228 | }
229 | ],
230 | borders: [
231 | {
232 | color: '#0000001A',
233 | fillType: Style.FillType.Color,
234 | position: Style.BorderPosition.Inside
235 | }
236 | ]
237 | }
238 | });
239 | }
240 |
241 | });
242 |
243 | document.save(libraryPath, error => {
244 | if (error) {
245 | UI.message('Error: ' + error.message);
246 | } else {
247 | Library.getLibraryForDocumentAtPath(libraryPath);
248 |
249 | // Remove library files that remove from Libraries Preferences
250 | let allLibraries = sketch.getLibraries().map(item => {
251 | return String(item.sketchObject.locationOnDisk().path());
252 | });
253 | let colorLibraryFiles = readdirSync(libraryFolder).filter(item => {
254 | return extname(item) === '.sketch';
255 | }).map(item => {
256 | return libraryFolder + item;
257 | });
258 | colorLibraryFiles.forEach(item => {
259 | if (!allLibraries.includes(item)) {
260 | unlinkSync(item);
261 | }
262 | });
263 |
264 | UI.message('Colors have imported as a library.');
265 | }
266 | });
267 |
268 | }
269 | }
270 | );
271 |
272 | }
273 |
274 | else if (identifier === 'import-colors-and-update-color-variables') {
275 | let document = sketch.getSelectedDocument();
276 | let swatches = document.swatches;
277 | let names = swatches.map(item => item.name);
278 | let countNew = 0;
279 | let countUpdate = 0;
280 | colors.forEach(item => {
281 | if (names.includes(item.name)) {
282 | let mscolor = color.mscolorWithHex(item.color);
283 | let swatch = swatches.find(_item => _item.name === item.name);
284 | swatch.sketchObject.updateWithColor(mscolor);
285 | let swatchContainer = document._getMSDocumentData().sharedSwatches();
286 | swatchContainer.updateReferencesToSwatch(swatch.sketchObject);
287 | countUpdate ++;
288 | } else {
289 | swatches.push(Swatch.from({
290 | name: item.name,
291 | color: item.color
292 | }));
293 | countNew ++;
294 | }
295 | UI.message(`Add: ${countNew}, Update: ${countUpdate}.`);
296 | });
297 | }
298 | });
299 | }
--------------------------------------------------------------------------------
/src/lib/aco-to-colors.js:
--------------------------------------------------------------------------------
1 | import { UI } from 'sketch';
2 | import { Buffer } from 'buffer';
3 | import { readFileSync } from '@skpm/fs';
4 | import color from './color';
5 |
6 | /**
7 | * Convert Adobe color swatch (ACO) file to Array [{name, color}]
8 | * File format specification:
9 | * https://www.adobe.com/devnet-apps/photoshop/fileformatashtml/#50577411_pgfId-1055819
10 | * http://www.nomodes.com/aco.html
11 | * @param {String} filePath
12 | * @returns {Array} [ {name, color} ]
13 | */
14 | export default function(filePath) {
15 |
16 | let colorContents = readFileSync(filePath);
17 | let colorBuffer = Buffer.from(colorContents);
18 |
19 | if (colorBuffer.length < 4) {
20 | UI.message('Error: Not a Adobe color swatch (ACO) file.');
21 | return;
22 | }
23 |
24 | let version = colorBuffer.slice(0, 2).readUInt16BE(0);
25 | let count = colorBuffer.slice(2, 4).readUInt16BE(0);
26 |
27 | let colors = [];
28 |
29 | // version 1
30 | let i;
31 | if (version === 1 && (colorBuffer.length - 4) / 10 === count) {
32 | i = 4;
33 | while (i < colorBuffer.length) {
34 | let colorSpace = colorBuffer.slice(i, i + 2).readUInt16BE(0);
35 | let w = colorBuffer.slice(i + 2, i + 4).readUInt16BE(0);
36 | let x = colorBuffer.slice(i + 4, i + 6).readUInt16BE(0);
37 | let y = colorBuffer.slice(i + 6, i + 8).readUInt16BE(0);
38 | let z = colorBuffer.slice(i + 8, i + 10).readUInt16BE(0);
39 | let nscolor = color.colorFromAco(colorSpace, w, x, y, z);
40 | let hexValue = color.toHexValue(nscolor);
41 | colors.push({
42 | name: null,
43 | color: hexValue
44 | });
45 | i += 10;
46 | }
47 | }
48 |
49 | // version 2
50 | if (
51 | (version === 2) ||
52 | (
53 | version === 1 &&
54 | colorBuffer.length > count * 10 + 8 &&
55 | colorBuffer.slice(4 + count * 10, 6 + count * 10).readUInt16BE(0) === 2 &&
56 | colorBuffer.slice(6 + count * 10, 8 + count * 10).readUInt16BE(0) === count
57 | )
58 | ) {
59 | i = 4 + count * 10 + 4;
60 | if (version === 2) {
61 | i = 4;
62 | }
63 | while (i < colorBuffer.length) {
64 | let colorSpace = colorBuffer.slice(i, i + 2).readUInt16BE(0);
65 | let w = colorBuffer.slice(i + 2, i + 4).readUInt16BE(0);
66 | let x = colorBuffer.slice(i + 4, i + 6).readUInt16BE(0);
67 | let y = colorBuffer.slice(i + 6, i + 8).readUInt16BE(0);
68 | let z = colorBuffer.slice(i + 8, i + 10).readUInt16BE(0);
69 | let colorName = '';
70 | let nameLength = colorBuffer.slice(i + 12, i + 14).readUInt16BE(0);
71 | for (let j = 0; j < nameLength * 2 - 2; j += 2) {
72 | colorName += String.fromCodePoint(colorBuffer.slice(i + 14 + j, i + 16 + j).readUInt16BE(0));
73 | }
74 | let nscolor = color.colorFromAco(colorSpace, w, x, y, z);
75 | let hexValue = color.toHexValue(nscolor);
76 | colors.push({
77 | name: colorName,
78 | color: hexValue
79 | });
80 | i += 14 + nameLength * 2;
81 | }
82 | }
83 |
84 | return colors;
85 | }
--------------------------------------------------------------------------------
/src/lib/act-to-colors.js:
--------------------------------------------------------------------------------
1 | import { UI } from 'sketch';
2 | import { Buffer } from 'buffer';
3 | import { readFileSync } from '@skpm/fs';
4 | import color from './color';
5 |
6 | /**
7 | * Convert Adobe Color Table (ACT) file to Array [{ name, color }]
8 | * File format specification:
9 | * https://www.adobe.com/devnet-apps/photoshop/fileformatashtml/#50577411_pgfId-1070626
10 | * @param {string} filePath
11 | * @returns {Array} [ {name, color} ]
12 | */
13 | export default function(filePath) {
14 | let colorContents = readFileSync(filePath);
15 | let colorBuffer = Buffer.from(colorContents);
16 |
17 | // should be 768 or 772 bytes long
18 | if (colorBuffer.length !== 768 && colorBuffer.length !== 772) {
19 | UI.message('Error: Not a valid Adobe Color Table (ACT) file.');
20 | return;
21 | }
22 |
23 | let numColors = 255;
24 |
25 | // If file is 772 bytes long, there are 4 additional bytes remaining
26 | if (colorBuffer.length === 772) {
27 | // Two bytes for the number of colors to use.
28 | numColors = colorBuffer.slice(-4).readInt16BE();
29 | }
30 |
31 | let colors = [];
32 |
33 | let i = 0;
34 |
35 | while (i < numColors * 3) {
36 | let r = colorBuffer.slice(i, i + 1).readUInt8(0);
37 | let g = colorBuffer.slice(i + 1, i + 2).readUInt8(0);
38 | let b = colorBuffer.slice(i + 2, i + 3).readUInt8(0);
39 |
40 | const nscolor = color.colorWithRGBA(r, g, b, 1);
41 | const hexValue = color.toHexValue(nscolor);
42 |
43 | colors.push({
44 | name: hexValue,
45 | color: hexValue,
46 | });
47 |
48 | i += 3;
49 | }
50 |
51 | return colors;
52 | }
53 |
--------------------------------------------------------------------------------
/src/lib/ase-to-colors.js:
--------------------------------------------------------------------------------
1 | import { UI } from 'sketch';
2 | import { Buffer } from 'buffer';
3 | import { readFileSync } from '@skpm/fs';
4 | import color from './color';
5 |
6 | /**
7 | * Convert Adobe Swatch Exchange (ASE) file to Array [{name, color}]
8 | * File format specification:
9 | * http://www.selapa.net/swatches/colors/fileformats.php#adobe_ase
10 | * @param {String} filePath
11 | * @returns {Array} [ {name, color} ]
12 | */
13 | export default function(filePath) {
14 |
15 | let colorContents = readFileSync(filePath);
16 | let colorBuffer = Buffer.from(colorContents);
17 | let signature = colorBuffer.toString('utf-8', 0, 4);
18 | let versionMajor = colorBuffer.slice(4, 6).readInt16BE(0);
19 | let versionMin = colorBuffer.slice(6, 8).readInt16BE(0);
20 | let count = colorBuffer.slice(8, 12).readInt32BE(0);
21 |
22 | if (colorBuffer.length > 12 && signature !== 'ASEF' && versionMajor !== 1 && versionMin !== 0) {
23 | UI.message('Error: Not Adobe Swatch Exchange (ASE) file.');
24 | return;
25 | }
26 |
27 | let colors = [];
28 |
29 | let i = 12;
30 | while (i < colorBuffer.length) {
31 |
32 | let blockLength;
33 | let blockType = colorBuffer.slice(i, i + 2).readInt16BE(0).toString(16);
34 | i += 2;
35 |
36 | // Ignore group start c001, end c002
37 | if (blockType === 'c001') {
38 | blockLength = colorBuffer.slice(i, i + 4).readInt32BE(0);
39 | i += blockLength;
40 | }
41 | if (blockType === 'c002') {
42 | i += 2;
43 | }
44 |
45 | // Color entry, start 0001
46 | if (blockType === '1') {
47 | blockLength = colorBuffer.slice(i, i + 4).readInt32BE(0);
48 | let nameLength = colorBuffer.slice(i + 4, i + 6).readUInt16BE(0);
49 | let colorName = '';
50 | let nscolor;
51 | for (let j = 0; j < nameLength * 2 - 2; j += 2) {
52 | colorName += String.fromCodePoint(colorBuffer.slice(i + 6 + j, i + 8 + j).readInt16BE(0));
53 | }
54 | let _i = i + 6 + nameLength * 2;
55 | let colorModel = colorBuffer.slice(_i, _i + 4).toString('utf-8', 0, 4);
56 | _i += 4;
57 | if (colorModel === 'RGB ') {
58 | let r = colorBuffer.slice(_i, _i + 4).readFloatBE(0);
59 | _i += 4;
60 | let g = colorBuffer.slice(_i, _i + 4).readFloatBE(0);
61 | _i += 4;
62 | let b = colorBuffer.slice(_i, _i + 4).readFloatBE(0);
63 | nscolor = color.colorWithRGBA(r * 255, g * 255, b * 255, 1.0);
64 | } else if (colorModel === 'CMYK') {
65 | let c = colorBuffer.slice(_i, _i + 4).readFloatBE(0);
66 | _i += 4;
67 | let m = colorBuffer.slice(_i, _i + 4).readFloatBE(0);
68 | _i += 4;
69 | let y = colorBuffer.slice(_i, _i + 4).readFloatBE(0);
70 | _i += 4;
71 | let k = colorBuffer.slice(_i, _i + 4).readFloatBE(0);
72 | nscolor = color.colorWithCMYKA(c * 100, m * 100, y * 100, k * 100, 1.0);
73 | } else if (colorModel === 'LAB ') {
74 | let l = colorBuffer.slice(_i, _i + 4).readFloatBE(0);
75 | _i += 4;
76 | let a = colorBuffer.slice(_i, _i + 4).readFloatBE(0);
77 | _i += 4;
78 | let b = colorBuffer.slice(_i, _i + 4).readFloatBE(0);
79 | nscolor = color.colorWithLABA(l * 100, a * 100, b * 100, 1.0);
80 | } else if (colorModel === 'Gray') {
81 | let g = colorBuffer.slice(_i, _i + 4).readFloatBE(0);
82 | nscolor = color.colorWithGA((1 - g) * 100, 1.0);
83 | }
84 |
85 | let hexValue = color.toHexValue(nscolor);
86 | colors.push({
87 | name: colorName,
88 | color: hexValue
89 | });
90 |
91 | i += blockLength;
92 | }
93 | }
94 |
95 | return colors;
96 | }
--------------------------------------------------------------------------------
/src/lib/clr-to-colors.js:
--------------------------------------------------------------------------------
1 | import color from './color';
2 |
3 | /**
4 | * Read Apple CLR file, return a Array [{name, color}]
5 | * @param {String} filePath
6 | * @returns {Array} [ {name, color} ]
7 | */
8 | export default function(filePath) {
9 | let colorList = NSColorList.alloc().initWithName_fromFile(null, filePath);
10 | return color.toArray(colorList);
11 | }
12 |
--------------------------------------------------------------------------------
/src/lib/color.js:
--------------------------------------------------------------------------------
1 | export default {
2 |
3 | /**
4 | * @param {String} hexValue #[0-9A-F]{3,8}
5 | * @returns {NSColor} NSColor
6 | */
7 | colorWithHex (hexValue) {
8 | return MSImmutableColor.colorWithSVGString(hexValue).NSColorWithColorSpace(nil);
9 | },
10 |
11 | /**
12 | * @param {String} hexValue #[0-9A-F]{3,8}
13 | * @returns {MSColor} MSColor
14 | */
15 | mscolorWithHex (hexValue) {
16 | return MSImmutableColor.colorWithSVGString(hexValue).newMutableCounterpart();
17 | },
18 |
19 | /**
20 | * @param {Number} r 0..255
21 | * @param {Number} g 0..255
22 | * @param {Number} b 0..255
23 | * @param {Number} a 0..1
24 | * @returns {NSColor} NSColor
25 | */
26 | colorWithRGBA (r, g, b, a) {
27 | return NSColor.colorWithRed_green_blue_alpha(r / 255, g / 255, b / 255, a);
28 | },
29 |
30 | /**
31 | * @param {Number} h 0..360
32 | * @param {Number} s 0..100
33 | * @param {Number} l 0..100
34 | * @param {Number} a 0..1
35 | * @returns {NSColor} NSColor
36 | */
37 | colorWithHSLA (h, s, l, a) {
38 | h = h / 360;
39 | s = s / 100;
40 | l = l / 100;
41 | let r, g, b;
42 | if (s == 0) {
43 | r = g = b = l; // achromatic
44 | } else {
45 | function hue2rgb(p, q, t){
46 | if(t < 0) t += 1;
47 | if(t > 1) t -= 1;
48 | if(t < 1 / 6) return p + (q - p) * 6 * t;
49 | if(t < 1 / 2) return q;
50 | if(t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
51 | return p;
52 | }
53 | let q = l < 0.5 ? l * (1 + s) : l + s - l * s;
54 | let p = 2 * l - q;
55 | r = hue2rgb(p, q, h + 1 / 3);
56 | g = hue2rgb(p, q, h);
57 | b = hue2rgb(p, q, h - 1 / 3);
58 | }
59 | return NSColor.colorWithRed_green_blue_alpha(r, g, b, a);
60 | },
61 |
62 | /**
63 | * @param {Number} h 0..360
64 | * @param {Number} s 0..100
65 | * @param {Number} b 0..100
66 | * @param {Number} a 0..1
67 | * @returns {NSColor} NSColor
68 | */
69 | colorWithHSBA (h, s, b, a) {
70 | return NSColor.colorWithHue_saturation_brightness_alpha(h / 360, s / 100, b / 100, a);
71 | },
72 |
73 | /**
74 | * @param {String} name CSS color name
75 | * @returns {NSColor} NSColor
76 | */
77 | colorWithName (name) {
78 | let colors = {
79 | 'aliceblue': [240, 248, 255],
80 | 'antiquewhite': [250, 235, 215],
81 | 'aqua': [0, 255, 255],
82 | 'aquamarine': [127, 255, 212],
83 | 'azure': [240, 255, 255],
84 | 'beige': [245, 245, 220],
85 | 'bisque': [255, 228, 196],
86 | 'black': [0, 0, 0],
87 | 'blanchedalmond': [255, 235, 205],
88 | 'blue': [0, 0, 255],
89 | 'blueviolet': [138, 43, 226],
90 | 'brown': [165, 42, 42],
91 | 'burlywood': [222, 184, 135],
92 | 'cadetblue': [95, 158, 160],
93 | 'chartreuse': [127, 255, 0],
94 | 'chocolate': [210, 105, 30],
95 | 'coral': [255, 127, 80],
96 | 'cornflowerblue': [100, 149, 237],
97 | 'cornsilk': [255, 248, 220],
98 | 'crimson': [220, 20, 60],
99 | 'cyan': [0, 255, 255],
100 | 'darkblue': [0, 0, 139],
101 | 'darkcyan': [0, 139, 139],
102 | 'darkgoldenrod': [184, 134, 11],
103 | 'darkgray': [169, 169, 169],
104 | 'darkgreen': [0, 100, 0],
105 | 'darkgrey': [169, 169, 169],
106 | 'darkkhaki': [189, 183, 107],
107 | 'darkmagenta': [139, 0, 139],
108 | 'darkolivegreen': [85, 107, 47],
109 | 'darkorange': [255, 140, 0],
110 | 'darkorchid': [153, 50, 204],
111 | 'darkred': [139, 0, 0],
112 | 'darksalmon': [233, 150, 122],
113 | 'darkseagreen': [143, 188, 143],
114 | 'darkslateblue': [72, 61, 139],
115 | 'darkslategray': [47, 79, 79],
116 | 'darkslategrey': [47, 79, 79],
117 | 'darkturquoise': [0, 206, 209],
118 | 'darkviolet': [148, 0, 211],
119 | 'deeppink': [255, 20, 147],
120 | 'deepskyblue': [0, 191, 255],
121 | 'dimgray': [105, 105, 105],
122 | 'dimgrey': [105, 105, 105],
123 | 'dodgerblue': [30, 144, 255],
124 | 'firebrick': [178, 34, 34],
125 | 'floralwhite': [255, 250, 240],
126 | 'forestgreen': [34, 139, 34],
127 | 'fuchsia': [255, 0, 255],
128 | 'gainsboro': [220, 220, 220],
129 | 'ghostwhite': [248, 248, 255],
130 | 'gold': [255, 215, 0],
131 | 'goldenrod': [218, 165, 32],
132 | 'gray': [128, 128, 128],
133 | 'green': [0, 128, 0],
134 | 'greenyellow': [173, 255, 47],
135 | 'grey': [128, 128, 128],
136 | 'honeydew': [240, 255, 240],
137 | 'hotpink': [255, 105, 180],
138 | 'indianred': [205, 92, 92],
139 | 'indigo': [75, 0, 130],
140 | 'ivory': [255, 255, 240],
141 | 'khaki': [240, 230, 140],
142 | 'lavender': [230, 230, 250],
143 | 'lavenderblush': [255, 240, 245],
144 | 'lawngreen': [124, 252, 0],
145 | 'lemonchiffon': [255, 250, 205],
146 | 'lightblue': [173, 216, 230],
147 | 'lightcoral': [240, 128, 128],
148 | 'lightcyan': [224, 255, 255],
149 | 'lightgoldenrodyellow': [250, 250, 210],
150 | 'lightgray': [211, 211, 211],
151 | 'lightgreen': [144, 238, 144],
152 | 'lightgrey': [211, 211, 211],
153 | 'lightpink': [255, 182, 193],
154 | 'lightsalmon': [255, 160, 122],
155 | 'lightseagreen': [32, 178, 170],
156 | 'lightskyblue': [135, 206, 250],
157 | 'lightslategray': [119, 136, 153],
158 | 'lightslategrey': [119, 136, 153],
159 | 'lightsteelblue': [176, 196, 222],
160 | 'lightyellow': [255, 255, 224],
161 | 'lime': [0, 255, 0],
162 | 'limegreen': [50, 205, 50],
163 | 'linen': [250, 240, 230],
164 | 'magenta': [255, 0, 255],
165 | 'maroon': [128, 0, 0],
166 | 'mediumaquamarine': [102, 205, 170],
167 | 'mediumblue': [0, 0, 205],
168 | 'mediumorchid': [186, 85, 211],
169 | 'mediumpurple': [147, 112, 219],
170 | 'mediumseagreen': [60, 179, 113],
171 | 'mediumslateblue': [123, 104, 238],
172 | 'mediumspringgreen': [0, 250, 154],
173 | 'mediumturquoise': [72, 209, 204],
174 | 'mediumvioletred': [199, 21, 133],
175 | 'midnightblue': [25, 25, 112],
176 | 'mintcream': [245, 255, 250],
177 | 'mistyrose': [255, 228, 225],
178 | 'moccasin': [255, 228, 181],
179 | 'navajowhite': [255, 222, 173],
180 | 'navy': [0, 0, 128],
181 | 'oldlace': [253, 245, 230],
182 | 'olive': [128, 128, 0],
183 | 'olivedrab': [107, 142, 35],
184 | 'orange': [255, 165, 0],
185 | 'orangered': [255, 69, 0],
186 | 'orchid': [218, 112, 214],
187 | 'palegoldenrod': [238, 232, 170],
188 | 'palegreen': [152, 251, 152],
189 | 'paleturquoise': [175, 238, 238],
190 | 'palevioletred': [219, 112, 147],
191 | 'papayawhip': [255, 239, 213],
192 | 'peachpuff': [255, 218, 185],
193 | 'peru': [205, 133, 63],
194 | 'pink': [255, 192, 203],
195 | 'plum': [221, 160, 221],
196 | 'powderblue': [176, 224, 230],
197 | 'purple': [128, 0, 128],
198 | 'rebeccapurple': [102, 51, 153],
199 | 'red': [255, 0, 0],
200 | 'rosybrown': [188, 143, 143],
201 | 'royalblue': [65, 105, 225],
202 | 'saddlebrown': [139, 69, 19],
203 | 'salmon': [250, 128, 114],
204 | 'sandybrown': [244, 164, 96],
205 | 'seagreen': [46, 139, 87],
206 | 'seashell': [255, 245, 238],
207 | 'sienna': [160, 82, 45],
208 | 'silver': [192, 192, 192],
209 | 'skyblue': [135, 206, 235],
210 | 'slateblue': [106, 90, 205],
211 | 'slategray': [112, 128, 144],
212 | 'slategrey': [112, 128, 144],
213 | 'snow': [255, 250, 250],
214 | 'springgreen': [0, 255, 127],
215 | 'steelblue': [70, 130, 180],
216 | 'tan': [210, 180, 140],
217 | 'teal': [0, 128, 128],
218 | 'thistle': [216, 191, 216],
219 | 'tomato': [255, 99, 71],
220 | 'turquoise': [64, 224, 208],
221 | 'violet': [238, 130, 238],
222 | 'wheat': [245, 222, 179],
223 | 'white': [255, 255, 255],
224 | 'whitesmoke': [245, 245, 245],
225 | 'yellow': [255, 255, 0],
226 | 'yellowgreen': [154, 205, 50]
227 | };
228 | if (colors[name.toLowerCase()]) {
229 | let r = colors[name][0] / 255;
230 | let g = colors[name][1] / 255;
231 | let b = colors[name][2] / 255;
232 | return NSColor.colorWithRed_green_blue_alpha(r, g, b, 1);
233 | } else {
234 | return null;
235 | }
236 | },
237 |
238 | /**
239 | * @param {Number} c 0..100
240 | * @param {Number} m 0..100
241 | * @param {Number} y 0..100
242 | * @param {Number} k 0..100
243 | * @param {Number} a 0..1
244 | * @returns {NSColor} NSColor
245 | */
246 | colorWithCMYKA (c, m, y, k, a) {
247 | return NSColor.colorWithDeviceCyan_magenta_yellow_black_alpha(c / 100, m / 100, y / 100, k / 100, a);
248 | },
249 |
250 | /**
251 | * http://www.easyrgb.com/en/math.php
252 | * @param {Number} l 0..100
253 | * @param {Number} a -128..127
254 | * @param {Number} b -128..127
255 | * @param {Number} alpha 0..1
256 | * @returns {NSColor} NSColor
257 | */
258 | colorWithLABA (l, a, b, alpha) {
259 | // CIE lab to CIE XYZ
260 | let y = (l + 16) / 116;
261 | let x = a / 500 + y;
262 | let z = y - b / 200;
263 |
264 | y = y * y * y > 0.008856 ? y * y * y : (y - 16 / 116) / 7.787;
265 | x = x * x * x > 0.008856 ? x * x * x : (x - 16 / 116) / 7.787;
266 | z = z * z * z > 0.008856 ? z * z * z : (z - 16 / 116) / 7.787;
267 |
268 | // D65
269 | x = x * 95.047;
270 | y = y * 100;
271 | z = z * 108.883;
272 |
273 | // CIE XYZ to sRGB
274 | x = x / 100;
275 | y = y / 100;
276 | z = z / 100;
277 |
278 | let R = x * 3.2406 + y * -1.5372 + z * -0.4986;
279 | let G = x * -0.9689 + y * 1.8758 + z * 0.0415;
280 | let B = x * 0.0557 + y * -0.2040 + z * 1.0570;
281 |
282 | R = R > 0.0031308 ? 1.055 * Math.pow(R, 1 / 2.4) - 0.055 : 12.92 * R;
283 | G = G > 0.0031308 ? 1.055 * Math.pow(G, 1 / 2.4) - 0.055 : 12.92 * G;
284 | B = B > 0.0031308 ? 1.055 * Math.pow(B, 1 / 2.4) - 0.055 : 12.92 * B;
285 |
286 | R = Math.min(Math.max(0, R), 1);
287 | G = Math.min(Math.max(0, G), 1);
288 | b = Math.min(Math.max(0, B), 1);
289 |
290 | return NSColor.colorWithRed_green_blue_alpha(R, G, B, alpha);
291 | },
292 |
293 | /**
294 | * @param {Number} g grayscale 0..100 white..black
295 | * @param {Number} a 0..1
296 | * @returns {NSColor} NSColor
297 | */
298 | colorWithGA (g, a) {
299 | return NSColor.colorWithWhite_alpha(1 - g / 100, a);
300 | },
301 |
302 | /**
303 | * http://www.nomodes.com/aco.html
304 | * @param {Number} colorSpace 0: RGB, 1: HSB, 2: CMYK, 7: LAB, 8: Grayscale, 9, Wide CMYK
305 | * @param {Number} w
306 | * @param {Number} x
307 | * @param {Number} y
308 | * @param {Number} z
309 | * @returns {NSColor} NSColor
310 | */
311 | colorFromAco (colorSpace, w, x, y, z) {
312 | if (colorSpace === 0) {
313 | // w: 0..65535, x: 0..65535, y: 0..65535, z: 0
314 | return this.colorWithRGBA(w / 65535 * 255, x / 65535 * 255, y / 65535 * 255, 1.0);
315 | } else if (colorSpace === 1) {
316 | // w: 0..65535, x: 0..65535, y: 0..65535, z: 0
317 | return this.colorWithHSBA(w / 65535 * 360, x / 65535 * 100, y / 65535 * 100, 1.0);
318 | } else if (colorSpace === 2) {
319 | // w: 0..65535, x: 0..65535, y: 0..65535, z: 0..65535
320 | return this.colorWithCMYKA(100 - w / 65535 * 100, 100 - x / 65535 * 100, 100 - y / 65535 * 100, 100 - z / 65535 * 100, 1.0);
321 | } else if (colorSpace === 7) {
322 | // w: 0..10000, x: -12800..12700, y: -12800..12700, z: 0
323 | if (x > 12700) {
324 | x = x - 65535;
325 | }
326 | if (y > 12700) {
327 | y = y - 65535;
328 | }
329 | return this.colorWithLABA(w / 100, x / 100, y / 100, 1.0);
330 |
331 | } else if (colorSpace === 8) {
332 | // w: 0..10000, x: 0, y: 0, z: 0
333 | return this.colorWithGA(w / 10000 * 100, 1.0);
334 | } else if (colorSpace === 9) {
335 | // w: 0..10000, x: 0..10000, y: 0..10000, z: 0..10000
336 | return this.colorWithCMYKA(w / 10000 * 100, x / 10000 * 100, y / 10000 * 100, z / 10000 * 100, 1.0);
337 | } else {
338 | return null;
339 | }
340 | },
341 |
342 | /**
343 | * @param {NSColor} nscolor
344 | * @param {String} key
345 | * @param {NSColorList} colorList
346 | * @param {Object} keyCount
347 | */
348 | addColorToList (nscolor, key, colorList, keyCount) {
349 | if (!isNaN(keyCount[key])) {
350 | keyCount[key] ++;
351 | } else {
352 | keyCount[key] = 1;
353 | }
354 | if (keyCount[key] === 1) {
355 | colorList.setColor_forKey(nscolor, key);
356 | } else {
357 | colorList.setColor_forKey(nscolor, key + ' ' + keyCount[key]);
358 | }
359 | },
360 |
361 | /**
362 | * @param {Array} colorsArray
363 | * @returns {NSColorList} NSColorList
364 | */
365 | colorListFromArray (colorsArray) {
366 | let colorList = NSColorList.alloc().initWithName(null);
367 | let keyCount = {};
368 | colorsArray.forEach(item => {
369 | let nscolor = this.colorWithHex(item.color);
370 | let colorName = item.name || item.color;
371 | this.addColorToList(nscolor, colorName, colorList, keyCount);
372 | });
373 | return colorList;
374 | },
375 |
376 | /**
377 | * @param {NSColor} nscolor
378 | * @returns {String} [0-9A-F]{6|8}
379 | */
380 | toHexValue (nscolor) {
381 | let color;
382 | if (String(nscolor.class()) === 'MSColor') {
383 | color = nscolor;
384 | } else {
385 | color = MSColor.colorWithNSColor(nscolor);
386 | }
387 | if (color.alpha() === 1) {
388 | return '#' + String(color.immutableModelObject().hexValue());
389 | } else {
390 | return '#' + String(color.immutableModelObject().hexValue()) + this.floatToHex(color.alpha());
391 | }
392 | },
393 |
394 | /**
395 | * @param {Number} f 0..1
396 | * @returns {String} [A-F]
397 | */
398 | floatToHex (f) {
399 | let hex = Math.round(f * 255).toString(16);
400 | if (hex.length === 1) {
401 | hex = '0' + hex;
402 | }
403 | return hex.toUpperCase();
404 | },
405 |
406 | /**
407 | * @param {String} name
408 | * @param {String} hexValue #ffffff, #ffffffff
409 | * @returns {MSColorAsset} MSColorAsset
410 | */
411 | colorAsset (name, hexValue) {
412 | let mscolor = MSImmutableColor.colorWithSVGString(hexValue).newMutableCounterpart();
413 | return MSColorAsset.alloc().initWithAsset_name(mscolor, name);
414 | },
415 |
416 | /**
417 | * @param {String} name
418 | * @param {Number} red 0..1
419 | * @param {Number} green 0..1
420 | * @param {Number} blue 0..1
421 | * @param {Number} alpha 0..1
422 | * @returns {MSColorAsset} MSColorAsset
423 | */
424 | colorAssetWithName_red_green_blue_alpha (name, red, green, blue, alpha) {
425 | let mscolor = MSColor.colorWithRed_green_blue_alpha(red, green, blue, alpha);
426 | return MSColorAsset.alloc().initWithAsset_name(mscolor, name);
427 | },
428 |
429 | /**
430 | * @param {NSColorList} colorList
431 | * @returns {Array} [{name, color}]
432 | */
433 | toArray (colorList) {
434 | let colors = [];
435 | colorList.allKeys().forEach(key => {
436 | let nscolor = colorList.colorWithKey(key);
437 | colors.push({
438 | name: key,
439 | color: this.toHexValue(nscolor),
440 | });
441 | });
442 | return colors;
443 | },
444 |
445 | /**
446 | * @param {String | Null} name
447 | * @returns {String | Null} String
448 | */
449 | cleanName (name) {
450 | if (name !== null) {
451 | name = name.replace(/\sCopy(\s\d+)?/, '');
452 | }
453 | return name;
454 | },
455 |
456 | /**
457 | * @param {Array} colorArray [{name, color}]
458 | * @param {Object} keyCount
459 | * @returns {String} name: #FFFFFF
460 | */
461 | toTextContent (colorArray, keyCount) {
462 | let text = '';
463 | colorArray.forEach(item => {
464 | let name = item.name;
465 | let color = item.color;
466 | if (!isNaN(keyCount[name])) {
467 | keyCount[name] ++;
468 | } else {
469 | keyCount[name] = 1;
470 | }
471 | if (keyCount[name] === 1) {
472 | name = item.name;
473 | } else {
474 | name += ' ' + keyCount[name];
475 | }
476 | if (/^#[0-9A-F]{6}FF$/i.test(item.color)) {
477 | color = item.color.substr(0, 7);
478 | }
479 | text += name + ': ' + color + '\n';
480 | });
481 | return text;
482 | }
483 |
484 | }
485 |
--------------------------------------------------------------------------------
/src/lib/gpl-to-colors.js:
--------------------------------------------------------------------------------
1 | import { UI } from 'sketch';
2 | import { EOL } from 'os';
3 | import { readFileSync } from '@skpm/fs';
4 | import color from './color';
5 |
6 | /**
7 | * Convert GIMP palette file to Array [{name, color}]
8 | * http://www.selapa.net/swatches/colors/fileformats.php#gimp_gpl
9 | * @param {String} filePath
10 | * @returns {Array} [ {name, color} ]
11 | */
12 | export default function(filePath) {
13 |
14 | let colorContents = readFileSync(filePath, 'utf-8');
15 | let lines = colorContents.split(EOL);
16 |
17 | if (lines.length < 2 && lines[0] !== 'GIMP Palette') {
18 | UI.message('Error: not a GIMP palette file.');
19 | return;
20 | }
21 |
22 | let colors = [];
23 |
24 | lines.forEach(line => {
25 | let regExpColor = new RegExp(/(\d+)[\t|\s]+(\d+)[\t|\s]+(\d+)[\t|\s]+(.*)/, '');
26 | if (regExpColor.test(line)) {
27 | let r = parseInt(line.match(regExpColor)[1]);
28 | let g = parseInt(line.match(regExpColor)[2]);
29 | let b = parseInt(line.match(regExpColor)[3]);
30 | let nscolor = color.colorWithRGBA(r, g, b, 1.0);
31 | let hexValue = color.toHexValue(nscolor);
32 | let colorName = line.match(regExpColor)[4] || null;
33 | colors.push({
34 | name: colorName,
35 | color: hexValue
36 | });
37 | }
38 | });
39 |
40 | return colors;
41 | }
--------------------------------------------------------------------------------
/src/lib/is-json-string.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Checking string is a JSON or not.
3 | * @param {String} str
4 | * @returns {Boolean}
5 | */
6 | export default function(str) {
7 | try {
8 | return JSON.parse(str) && true;
9 | } catch (err) {
10 | return false;
11 | }
12 | }
--------------------------------------------------------------------------------
/src/lib/is-zip.js:
--------------------------------------------------------------------------------
1 | import { Buffer } from 'buffer';
2 | import { readFileSync } from '@skpm/fs';
3 |
4 | /**
5 | * Checking a file is a ZIP or not.
6 | * @param {String} filePath
7 | * @returns {Boolean}
8 | */
9 | export default function(filePath) {
10 | let contents = readFileSync(filePath);
11 | let buffer = Buffer.from(contents);
12 |
13 | if (!buffer || buffer.length < 4) {
14 | return false;
15 | }
16 |
17 | return buffer[0] === 0x50 &&
18 | buffer[1] === 0x4B &&
19 | (buffer[2] === 0x03 || buffer[2] === 0x05 || buffer[2] === 0x07) &&
20 | (buffer[3] === 0x04 || buffer[3] === 0x06 || buffer[3] === 0x08);
21 | }
--------------------------------------------------------------------------------
/src/lib/sketch-to-colors.js:
--------------------------------------------------------------------------------
1 | import sketch from 'sketch/dom';
2 | import { UI } from 'sketch';
3 | import { Document } from 'sketch/dom';
4 |
5 | /**
6 | * Get colors from Sketch file.
7 | * @param {String} filePath
8 | * @returns {Array} [ {name, color} ]
9 | */
10 | export default function(filePath) {
11 |
12 | if (sketch.version.sketch >= 92) {
13 | filePath = NSURL.fileURLWithPath(filePath);
14 | }
15 |
16 | // Read data from sketch file.
17 | const error = MOPointer.alloc().init();
18 | const msDocument = MSDocument.alloc().init();
19 | msDocument.readFromURL_ofType_error(filePath, 'com.bohemiancoding.sketch.drawing', error);
20 |
21 | if (error.value() !== null) {
22 | UI.message('Error: Not a Sketch file.');
23 | return;
24 | }
25 |
26 | const document = Document.fromNative(msDocument);
27 |
28 | let colors;
29 | if (document.swatches.length > 0) {
30 | colors = document.swatches.map(item => {
31 | return {
32 | name: item.name,
33 | color: item.color
34 | };
35 | });
36 | } else {
37 | colors = document.colors.map(item => {
38 | return {
39 | name: item.name,
40 | color: item.color
41 | };
42 | });
43 | }
44 |
45 | return colors;
46 |
47 | }
--------------------------------------------------------------------------------
/src/lib/sketchpalette-to-colors.js:
--------------------------------------------------------------------------------
1 | import { readFileSync } from '@skpm/fs';
2 | import color from './color';
3 | import isJSONString from './is-json-string';
4 |
5 | /**
6 | * Get colors from Sketch .sketchpalette file.
7 | * @param {String} filePath
8 | * @returns {Array} [ {name, color} ]
9 | */
10 | export default function(filePath) {
11 |
12 | let assetContent = readFileSync(filePath, 'utf-8');
13 |
14 | if (isJSONString(assetContent)) {
15 | let colors = JSON.parse(assetContent).colors;
16 |
17 | colors = colors.map(item => {
18 | let nscolor = color.colorWithRGBA(
19 | item.red * 255,
20 | item.green * 255,
21 | item.blue * 255,
22 | item.alpha
23 | );
24 | let hexValue = color.toHexValue(nscolor);
25 | return {
26 | name: null,
27 | color: hexValue
28 | };
29 | });
30 |
31 | return colors;
32 | }
33 |
34 | }
--------------------------------------------------------------------------------
/src/lib/sketchpreset-to-colors.js:
--------------------------------------------------------------------------------
1 | import { readFileSync } from '@skpm/fs';
2 | import color from './color';
3 | import isJSONString from './is-json-string';
4 | import isZip from './is-zip';
5 | import sketch from 'sketch/dom';
6 | import { UI } from 'sketch';
7 | import { toArray } from 'util';
8 |
9 | /**
10 | * Get colors from Sketch .sketchpreset file.
11 | * @param {String} filePath
12 | * @returns {Array} [ {name, color} ]
13 | */
14 | export default function(filePath) {
15 |
16 | let assetContent = readFileSync(filePath, 'utf-8');
17 |
18 | // Sketch < 54 sketchpreset is JSON file
19 | if (isJSONString(assetContent)) {
20 | let colors = JSON.parse(assetContent).root.colorAssets;
21 |
22 | colors = colors.map(item => {
23 | let colorName = item.name;
24 | let nscolor = color.colorWithRGBA(
25 | item.color.red * 255,
26 | item.color.green * 255,
27 | item.color.blue * 255,
28 | item.color.alpha
29 | );
30 | let hexValue = color.toHexValue(nscolor);
31 | return {
32 | name: colorName,
33 | color: hexValue
34 | };
35 | });
36 |
37 | return colors;
38 | }
39 |
40 | // Sketch 54+ sketchpreset is ZIP file
41 | if (isZip(filePath)) {
42 | if (sketch.version.sketch >= 54) {
43 | let nativeAssets = MSPersistentAssetCollection.assetCollectionWithURL(NSURL.fileURLWithPath(filePath));
44 | let colors = toArray(nativeAssets.colorAssets()).map(asset => {
45 | let hexValue = color.toHexValue(asset.color());
46 | return {
47 | name: String(asset.name()),
48 | color: hexValue
49 | }
50 | });
51 | return colors;
52 | } else {
53 | UI.message('This sketch preset file need to open with Sketch 54+.');
54 | return;
55 | }
56 | }
57 |
58 | }
--------------------------------------------------------------------------------
/src/lib/txt-to-colors.js:
--------------------------------------------------------------------------------
1 | import { UI } from 'sketch';
2 | import { EOL } from 'os';
3 | import { readFileSync } from '@skpm/fs';
4 | import color from './color';
5 |
6 | /**
7 | * Get colors from text file.
8 | *
9 | * white: #FFFFFF
10 | * red: red
11 | * blue: rgb(0, 0, 255)
12 | * transparent blue: rgb(0, 0, 255, 0.5)
13 | * cyan: hsl(180, 100, 50)
14 | * transparent cyan: hsla(180, 100%, 50%, 0.5)
15 | *
16 | * @param {String} filePath
17 | * @returns {Array} [ {name, color} ]
18 | */
19 | export default function(filePath) {
20 |
21 | let colorContents = readFileSync(filePath, 'utf-8');
22 | let lines = colorContents.split(EOL);
23 | let colors = [];
24 |
25 | lines.forEach(line => {
26 | let lineRegExp = /^(.*):\s?(.*)$/;
27 | if (lineRegExp.test(line)) {
28 | let lineMatch = line.match(lineRegExp);
29 | let colorName = lineMatch[1];
30 | let colorValue = lineMatch[2];
31 | let hexValue;
32 | if (/^#[0-9a-f]{3,8}/i.test(colorValue)) {
33 | hexValue = colorValue.match(/^#[0-9a-f]{3,8}/i)[0];
34 | } else if (/^rgb[a]?\(.*\)/i.test(colorValue)) {
35 | let rgba = colorValue.match(/^rgb[a]?\((.*)\)/i)[1].split(/,\s?/);
36 | let nsColor = color.colorWithRGBA(parseInt(rgba[0]) || 0, parseInt(rgba[1]) || 0, parseInt(rgba[2]) || 0, parseFloat(rgba[3]) || 1);
37 | hexValue = color.toHexValue(nsColor);
38 | } else if (/^hsl[a]?\(.*\)/i.test(colorValue)) {
39 | let hsla = colorValue.match(/^hsl[a]?\((.*)\)/i)[1].split(/,\s?/);
40 | let nsColor = color.colorWithHSLA(parseInt(hsla[0]) || 0, parseInt(hsla[1]) || 0, parseInt(hsla[2]) || 0, parseFloat(hsla[3]) || 1);
41 | hexValue = color.toHexValue(nsColor);
42 | } else if (color.colorWithName(colorValue)) {
43 | hexValue = color.toHexValue(color.colorWithName(colorValue));
44 | }
45 | if (hexValue) {
46 | colors.push({
47 | name: colorName,
48 | color: hexValue
49 | });
50 | }
51 | }
52 | });
53 |
54 | if (colors.length === 0) {
55 | UI.message('Invalid format text file.');
56 | return;
57 | }
58 |
59 | return colors;
60 | }
--------------------------------------------------------------------------------
/src/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "compatibleVersion": 3,
3 | "bundleVersion": 1,
4 | "icon": "icon.png",
5 | "commands": [
6 | {
7 | "name": "Import Colors to Color Variables",
8 | "identifier": "import-colors-to-color-variables",
9 | "script": "./import.js"
10 | },
11 | {
12 | "name": "Import Colors as Library",
13 | "identifier": "import-colors-as-library",
14 | "script": "./import.js"
15 | },
16 | {
17 | "name": "Import Colors and Update Color Variables",
18 | "identifier": "import-colors-and-update-color-variables",
19 | "script": "./import.js"
20 | },
21 | {
22 | "name": "Convert Colors to .clr File",
23 | "identifier": "convert-colors-to-clr-file",
24 | "script": "./import.js"
25 | },
26 | {
27 | "name": "Convert Colors to .txt File",
28 | "identifier": "convert-colors-to-txt-file",
29 | "script": "./import.js"
30 | },
31 | {
32 | "name": "Export Color Variables to .clr File",
33 | "identifier": "export-color-variables-to-clr-file",
34 | "script": "./export.js"
35 | },
36 | {
37 | "name": "Export Color Variables to .txt File",
38 | "identifier": "export-color-variables-to-txt-file",
39 | "script": "./export.js"
40 | }
41 | ],
42 | "menu": {
43 | "title": "Import Colors",
44 | "items": [
45 | "import-colors-to-color-variables",
46 | "import-colors-as-library",
47 | "import-colors-and-update-color-variables",
48 | "-",
49 | "convert-colors-to-clr-file",
50 | "convert-colors-to-txt-file",
51 | "-",
52 | "export-color-variables-to-clr-file",
53 | "export-color-variables-to-txt-file"
54 | ]
55 | },
56 | "name": "Import Colors",
57 | "identifier" : "com.ashung.hung.import-colors-sketch",
58 | "homepage" : "https://github.com/Ashung/import-colors-sketch"
59 | }
--------------------------------------------------------------------------------
/webpack.skpm.config.js:
--------------------------------------------------------------------------------
1 | module.exports = function (config, entry) {
2 | config.mode = 'production';
3 | }
--------------------------------------------------------------------------------