material-icon-theme 4.17.0 → 4.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (203) hide show
  1. package/.eslintrc.json +51 -51
  2. package/.github/FUNDING.yml +3 -3
  3. package/.github/ISSUE_TEMPLATE/bug_report.md +34 -34
  4. package/.github/ISSUE_TEMPLATE/icon_request.md +27 -27
  5. package/.github/workflows/build.yml +45 -45
  6. package/.github/workflows/color-check.yml +22 -22
  7. package/.github/workflows/release.yml +73 -73
  8. package/.prettierrc +7 -7
  9. package/.vscode/extensions.json +3 -3
  10. package/.vscode/launch.json +43 -43
  11. package/.vscode/settings.json +14 -14
  12. package/.vscode/tasks.json +32 -32
  13. package/.vscodeignore +20 -20
  14. package/CHANGELOG.md +1171 -1152
  15. package/CONTRIBUTING.md +62 -62
  16. package/LICENSE.md +8 -8
  17. package/README.md +208 -208
  18. package/build/web-extension.webpack.config.js +62 -62
  19. package/build/webpack.config.js +39 -39
  20. package/changelog.config.json +4 -4
  21. package/icons/architecture.svg +4 -4
  22. package/icons/astyle.svg +4 -4
  23. package/icons/azure.svg +9 -9
  24. package/icons/blitz.svg +4 -4
  25. package/icons/buildkite.svg +8 -8
  26. package/icons/cypress.svg +4 -4
  27. package/icons/dart_generated.svg +9 -9
  28. package/icons/dependabot.svg +4 -4
  29. package/icons/dinophp.svg +16 -16
  30. package/icons/figma.svg +10 -10
  31. package/icons/folder-angular-open.svg +2 -2
  32. package/icons/folder-angular.svg +2 -2
  33. package/icons/folder-buildkite-open.svg +8 -8
  34. package/icons/folder-buildkite.svg +7 -7
  35. package/icons/folder-cypress-open.svg +5 -5
  36. package/icons/folder-cypress.svg +5 -5
  37. package/icons/folder-java-open.svg +2 -2
  38. package/icons/folder-java.svg +2 -2
  39. package/icons/folder-lua-open.svg +1 -0
  40. package/icons/folder-lua.svg +1 -0
  41. package/icons/folder-next-open.svg +2 -2
  42. package/icons/folder-next.svg +2 -2
  43. package/icons/folder-nuxt-open.svg +2 -2
  44. package/icons/folder-nuxt.svg +2 -2
  45. package/icons/folder-queue-open.svg +2 -2
  46. package/icons/folder-queue.svg +2 -2
  47. package/icons/folder-resolver-open.svg +2 -2
  48. package/icons/folder-resolver.svg +2 -2
  49. package/icons/folder-serverless-open.svg +5 -5
  50. package/icons/folder-serverless.svg +5 -5
  51. package/icons/folder-shader-open.svg +7 -7
  52. package/icons/folder-shader.svg +6 -6
  53. package/icons/folder-target-open.svg +2 -2
  54. package/icons/folder-target.svg +2 -2
  55. package/icons/folder-unity-open.svg +2 -2
  56. package/icons/folder-unity.svg +2 -2
  57. package/icons/folder-vercel-open.svg +4 -4
  58. package/icons/folder-vercel.svg +4 -4
  59. package/icons/folder-verdaccio-open.svg +8 -8
  60. package/icons/folder-verdaccio.svg +8 -8
  61. package/icons/gleam.svg +4 -4
  62. package/icons/gridsome.svg +4 -4
  63. package/icons/hardhat.svg +3 -3
  64. package/icons/lighthouse.svg +2 -2
  65. package/icons/ndst.svg +7 -7
  66. package/icons/next.svg +3 -3
  67. package/icons/next_light.svg +2 -2
  68. package/icons/nuxt.svg +5 -5
  69. package/icons/odin.svg +6 -6
  70. package/icons/otne.svg +16 -16
  71. package/icons/parcel.svg +4 -4
  72. package/icons/playwright.svg +7 -7
  73. package/icons/plop.svg +4 -4
  74. package/icons/pnpm.svg +9 -9
  75. package/icons/pnpm_light.svg +7 -7
  76. package/icons/poetry.svg +1 -1
  77. package/icons/processing.svg +10 -10
  78. package/icons/remix.svg +4 -4
  79. package/icons/remix_light.svg +4 -4
  80. package/icons/rescript-interface.svg +5 -0
  81. package/icons/rome.svg +5 -5
  82. package/icons/serverless.svg +4 -4
  83. package/icons/shader.svg +4 -4
  84. package/icons/siyuan.svg +9 -9
  85. package/icons/steadybit.svg +1 -1
  86. package/icons/svgr.svg +4 -4
  87. package/icons/tauri.svg +9 -9
  88. package/icons/template.svg +4 -4
  89. package/icons/tobi.svg +4 -4
  90. package/icons/tobimake.svg +14 -14
  91. package/icons/turborepo.svg +12 -12
  92. package/icons/turborepo_light.svg +12 -12
  93. package/icons/verdaccio.svg +5 -5
  94. package/images/contributors.png +0 -0
  95. package/images/fileIcons.png +0 -0
  96. package/images/folderIcons.png +0 -0
  97. package/logo.svg +21 -21
  98. package/material-colors.yml +257 -257
  99. package/package.json +264 -264
  100. package/package.nls.de.json +35 -35
  101. package/package.nls.es.json +32 -32
  102. package/package.nls.fr.json +32 -32
  103. package/package.nls.ja.json +35 -35
  104. package/package.nls.json +35 -35
  105. package/package.nls.nl.json +35 -35
  106. package/package.nls.pl.json +35 -35
  107. package/package.nls.pt-BR.json +32 -32
  108. package/package.nls.pt-PT.json +32 -32
  109. package/package.nls.ru.json +32 -32
  110. package/package.nls.zh-CN.json +32 -32
  111. package/package.nls.zh-TW.json +32 -32
  112. package/src/commands/activate.ts +26 -26
  113. package/src/commands/explorerArrows.ts +55 -55
  114. package/src/commands/folderColor.ts +96 -96
  115. package/src/commands/folders.ts +55 -55
  116. package/src/commands/grayscale.ts +55 -55
  117. package/src/commands/iconPacks.ts +68 -68
  118. package/src/commands/index.ts +30 -30
  119. package/src/commands/opacity.ts +46 -46
  120. package/src/commands/restoreConfig.ts +14 -14
  121. package/src/commands/saturation.ts +46 -46
  122. package/src/extension.ts +42 -35
  123. package/src/helpers/changeDetection.ts +73 -68
  124. package/src/helpers/customIcons.ts +8 -8
  125. package/src/helpers/fileConfig.ts +37 -37
  126. package/src/helpers/index.ts +100 -100
  127. package/src/helpers/objects.ts +58 -58
  128. package/src/helpers/types.ts +7 -7
  129. package/src/helpers/versioning.ts +73 -73
  130. package/src/i18n/index.ts +78 -78
  131. package/src/i18n/lang-de.ts +54 -54
  132. package/src/i18n/lang-en.ts +53 -53
  133. package/src/i18n/lang-es.ts +53 -53
  134. package/src/i18n/lang-fr.ts +53 -53
  135. package/src/i18n/lang-ja.ts +54 -54
  136. package/src/i18n/lang-nl.ts +54 -54
  137. package/src/i18n/lang-pl.ts +52 -52
  138. package/src/i18n/lang-pt-br.ts +53 -53
  139. package/src/i18n/lang-pt-pt.ts +53 -53
  140. package/src/i18n/lang-ru.ts +52 -52
  141. package/src/i18n/lang-uk.ts +54 -54
  142. package/src/i18n/lang-zh-cn.ts +52 -52
  143. package/src/i18n/lang-zh-tw.ts +52 -52
  144. package/src/icons/fileIcons.ts +2046 -1909
  145. package/src/icons/folderIcons.ts +773 -769
  146. package/src/icons/generator/constants.ts +29 -29
  147. package/src/icons/generator/fileGenerator.ts +216 -216
  148. package/src/icons/generator/folderGenerator.ts +340 -340
  149. package/src/icons/generator/iconOpacity.ts +111 -111
  150. package/src/icons/generator/iconSaturation.ts +140 -140
  151. package/src/icons/generator/index.ts +7 -7
  152. package/src/icons/generator/jsonGenerator.ts +187 -187
  153. package/src/icons/generator/languageGenerator.ts +127 -127
  154. package/src/icons/index.ts +4 -4
  155. package/src/icons/languageIcons.ts +136 -136
  156. package/src/messages/outdated.ts +33 -33
  157. package/src/messages/reload.ts +32 -32
  158. package/src/messages/start.ts +12 -12
  159. package/src/messages/update.ts +48 -48
  160. package/src/messages/welcome.ts +47 -47
  161. package/src/models/helpers/index.ts +1 -1
  162. package/src/models/helpers/themeStatus.ts +5 -5
  163. package/src/models/i18n/index.ts +1 -1
  164. package/src/models/i18n/translation.ts +50 -50
  165. package/src/models/iconConfiguration.ts +37 -37
  166. package/src/models/icons/defaultIcon.ts +16 -16
  167. package/src/models/icons/files/fileIcon.ts +49 -49
  168. package/src/models/icons/files/fileTypes.ts +14 -14
  169. package/src/models/icons/files/index.ts +2 -2
  170. package/src/models/icons/folders/folderIcon.ts +34 -34
  171. package/src/models/icons/folders/folderTheme.ts +23 -23
  172. package/src/models/icons/folders/index.ts +2 -2
  173. package/src/models/icons/iconJsonOptions.ts +23 -23
  174. package/src/models/icons/iconPack.ts +12 -12
  175. package/src/models/icons/index.ts +6 -6
  176. package/src/models/icons/languages/index.ts +1 -1
  177. package/src/models/icons/languages/languageIdentifier.ts +26 -26
  178. package/src/models/index.ts +4 -4
  179. package/src/models/scripts/contributors/contributor.ts +22 -22
  180. package/src/models/scripts/contributors/contributorsConfig.ts +10 -10
  181. package/src/scripts/contributors/contributors.css +24 -24
  182. package/src/scripts/contributors/index.ts +138 -138
  183. package/src/scripts/helpers/painter.ts +5 -5
  184. package/src/scripts/helpers/screenshots.ts +32 -32
  185. package/src/scripts/helpers/similarity.ts +47 -47
  186. package/src/scripts/helpers/titleCase.ts +7 -7
  187. package/src/scripts/icons/checks/checkIconAvailability.ts +215 -215
  188. package/src/scripts/icons/checks/checkIconConflicts.ts +154 -154
  189. package/src/scripts/icons/checks/checkIconUsage.ts +141 -141
  190. package/src/scripts/icons/checks/index.ts +7 -7
  191. package/src/scripts/icons/generateJson.ts +11 -11
  192. package/src/scripts/preview/index.ts +40 -40
  193. package/src/scripts/preview/preview.ts +165 -165
  194. package/src/scripts/preview/style.css +48 -48
  195. package/src/test/runTest.ts +26 -26
  196. package/src/test/spec/i18n/i18n.spec.ts +61 -61
  197. package/src/test/spec/icons/fileIcons.spec.ts +250 -250
  198. package/src/test/spec/icons/folderIcons.spec.ts +418 -418
  199. package/src/test/spec/icons/languageIcons.spec.ts +184 -184
  200. package/src/test/spec/index.ts +36 -36
  201. package/src/web/extension.ts +10 -10
  202. package/svgo.config.js +11 -11
  203. package/tsconfig.json +23 -23
@@ -1,340 +1,340 @@
1
- import * as fs from 'fs';
2
- import merge from 'lodash.merge';
3
- import * as path from 'path';
4
- import { getFileConfigHash } from '../../helpers/fileConfig';
5
- import {
6
- DefaultIcon,
7
- FolderIcon,
8
- FolderTheme,
9
- IconAssociations,
10
- IconConfiguration,
11
- IconJsonOptions,
12
- } from '../../models/index';
13
- import {
14
- highContrastColorFileEnding,
15
- iconFolderPath,
16
- lightColorFileEnding,
17
- openedFolder,
18
- } from './constants';
19
-
20
- /**
21
- * Get the folder icon definitions as object.
22
- */
23
- export const loadFolderIconDefinitions = (
24
- folderThemes: FolderTheme[],
25
- config: IconConfiguration,
26
- options: IconJsonOptions
27
- ): IconConfiguration => {
28
- config = merge({}, config);
29
- config.hidesExplorerArrows = options.hidesExplorerArrows;
30
- const activeTheme = getEnabledFolderTheme(
31
- folderThemes,
32
- options.folders?.theme
33
- );
34
- if (!activeTheme) {
35
- return {};
36
- }
37
- const enabledIcons = disableIconsByPack(activeTheme, options.activeIconPack);
38
- const customIcons = getCustomIcons(options.folders?.associations);
39
- const allIcons = [...enabledIcons, ...customIcons];
40
-
41
- if (options.folders?.theme === 'none') {
42
- return config;
43
- }
44
-
45
- allIcons.forEach((icon) => {
46
- if (icon.disabled) return;
47
- config = setIconDefinitions(config, icon);
48
- config = merge({}, config, setFolderNames(icon.name, icon.folderNames));
49
- config.light = icon.light
50
- ? merge(
51
- {},
52
- config.light,
53
- setFolderNames(icon.name, icon.folderNames, lightColorFileEnding)
54
- )
55
- : config.light;
56
- config.highContrast = icon.highContrast
57
- ? merge(
58
- {},
59
- config.highContrast,
60
- setFolderNames(
61
- icon.name,
62
- icon.folderNames,
63
- highContrastColorFileEnding
64
- )
65
- )
66
- : config.highContrast;
67
- });
68
-
69
- config = setDefaultFolderIcons(activeTheme, config);
70
- return config;
71
- };
72
-
73
- /**
74
- * Set the default folder icons for the theme.
75
- */
76
- const setDefaultFolderIcons = (
77
- theme: FolderTheme,
78
- config: IconConfiguration
79
- ): IconConfiguration => {
80
- config = merge({}, config);
81
- const hasFolderIcons =
82
- !!theme.defaultIcon.name && theme.defaultIcon.name.length > 0;
83
- if (hasFolderIcons) {
84
- config = setIconDefinitions(config, theme.defaultIcon);
85
- }
86
- config = merge(
87
- {},
88
- config,
89
- createDefaultIconConfigObject(hasFolderIcons, theme, '')
90
- );
91
- config.light = theme.defaultIcon.light
92
- ? merge(
93
- {},
94
- config.light,
95
- createDefaultIconConfigObject(
96
- hasFolderIcons,
97
- theme,
98
- lightColorFileEnding
99
- )
100
- )
101
- : config.light;
102
- config.highContrast = theme.defaultIcon.highContrast
103
- ? merge(
104
- {},
105
- config.highContrast,
106
- createDefaultIconConfigObject(
107
- hasFolderIcons,
108
- theme,
109
- highContrastColorFileEnding
110
- )
111
- )
112
- : config.highContrast;
113
-
114
- config = merge(
115
- {},
116
- config,
117
- createRootIconConfigObject(hasFolderIcons, theme, '')
118
- );
119
- if (theme.rootFolder) {
120
- config = setIconDefinitions(config, theme.rootFolder);
121
- config.light = theme.rootFolder.light
122
- ? merge(
123
- {},
124
- config.light,
125
- createRootIconConfigObject(
126
- hasFolderIcons,
127
- theme,
128
- lightColorFileEnding
129
- )
130
- )
131
- : config.light;
132
- config.highContrast = theme.rootFolder.highContrast
133
- ? merge(
134
- {},
135
- config.highContrast,
136
- createRootIconConfigObject(
137
- hasFolderIcons,
138
- theme,
139
- highContrastColorFileEnding
140
- )
141
- )
142
- : config.highContrast;
143
- }
144
-
145
- return config;
146
- };
147
-
148
- /**
149
- * Get the object of the current enabled theme.
150
- */
151
- const getEnabledFolderTheme = (
152
- themes: FolderTheme[],
153
- enabledTheme: string | undefined
154
- ): FolderTheme | undefined => {
155
- return themes.find((theme) => theme.name === enabledTheme);
156
- };
157
-
158
- /**
159
- * Disable all file icons that are in a pack which is disabled.
160
- */
161
- const disableIconsByPack = (
162
- folderIcons: FolderTheme | undefined,
163
- activatedIconPack: string | undefined
164
- ): FolderIcon[] => {
165
- if (!folderIcons?.icons || folderIcons.icons.length === 0) {
166
- return [];
167
- }
168
- return folderIcons.icons.filter((icon) => {
169
- return !icon.enabledFor
170
- ? true
171
- : icon.enabledFor.some((p) => p === activatedIconPack);
172
- });
173
- };
174
-
175
- const setIconDefinitions = (
176
- config: IconConfiguration,
177
- icon: FolderIcon | DefaultIcon
178
- ) => {
179
- config = merge({}, config);
180
- config = createIconDefinitions(config, icon.name);
181
- if (icon.light) {
182
- config = merge(
183
- {},
184
- config,
185
- createIconDefinitions(config, icon.name, lightColorFileEnding)
186
- );
187
- }
188
- if (icon.highContrast) {
189
- config = merge(
190
- {},
191
- config,
192
- createIconDefinitions(config, icon.name, highContrastColorFileEnding)
193
- );
194
- }
195
- return config;
196
- };
197
-
198
- const createIconDefinitions = (
199
- config: IconConfiguration,
200
- iconName: string,
201
- appendix: string = ''
202
- ) => {
203
- config = merge({}, config);
204
- const fileConfigHash = getFileConfigHash(config.options ?? {});
205
- const configIconDefinitions = config.iconDefinitions;
206
- if (configIconDefinitions) {
207
- configIconDefinitions[iconName + appendix] = {
208
- iconPath: `${iconFolderPath}${iconName}${appendix}${fileConfigHash}.svg`,
209
- };
210
- configIconDefinitions[`${iconName}${openedFolder}${appendix}`] = {
211
- iconPath: `${iconFolderPath}${iconName}${openedFolder}${appendix}${fileConfigHash}.svg`,
212
- };
213
- }
214
- return config;
215
- };
216
-
217
- const setFolderNames = (
218
- iconName: string,
219
- folderNames: string[],
220
- appendix: string = ''
221
- ) => {
222
- const obj: Partial<IconConfiguration> = {
223
- folderNames: {},
224
- folderNamesExpanded: {},
225
- };
226
- folderNames.forEach((name) => {
227
- if (obj.folderNames) {
228
- obj.folderNames[name as keyof IconConfiguration] = iconName + appendix;
229
- }
230
- if (obj.folderNamesExpanded) {
231
- obj.folderNamesExpanded[
232
- name as keyof IconConfiguration
233
- ] = `${iconName}${openedFolder}${appendix}`;
234
- }
235
- });
236
- return obj;
237
- };
238
-
239
- const createDefaultIconConfigObject = (
240
- hasFolderIcons: boolean,
241
- theme: FolderTheme,
242
- appendix: string = ''
243
- ) => {
244
- const obj = {
245
- folder: '',
246
- folderExpanded: '',
247
- };
248
- obj.folder = hasFolderIcons ? theme.defaultIcon.name + appendix : '';
249
- obj.folderExpanded = hasFolderIcons
250
- ? `${theme.defaultIcon.name}${openedFolder}${appendix}`
251
- : '';
252
- return obj;
253
- };
254
-
255
- const createRootIconConfigObject = (
256
- hasFolderIcons: boolean,
257
- theme: FolderTheme,
258
- appendix: string = ''
259
- ) => {
260
- const obj = {
261
- rootFolder: '',
262
- rootFolderExpanded: '',
263
- };
264
- obj.rootFolder = hasFolderIcons
265
- ? theme.rootFolder
266
- ? theme.rootFolder.name + appendix
267
- : theme.defaultIcon.name + appendix
268
- : '';
269
- obj.rootFolderExpanded = hasFolderIcons
270
- ? theme.rootFolder
271
- ? `${theme.rootFolder.name}${openedFolder}${appendix}`
272
- : `${theme.defaultIcon.name}${openedFolder}${appendix}`
273
- : '';
274
- return obj;
275
- };
276
-
277
- const getCustomIcons = (folderAssociations: IconAssociations | undefined) => {
278
- if (!folderAssociations) return [];
279
-
280
- const icons: FolderIcon[] = Object.keys(folderAssociations).map((fa) => ({
281
- // use default folder if icon name is empty
282
- name:
283
- folderAssociations[fa].length > 0
284
- ? 'folder-' + folderAssociations[fa].toLowerCase()
285
- : 'folder',
286
- folderNames: [fa.toLowerCase()],
287
- }));
288
-
289
- return icons;
290
- };
291
-
292
- export const generateFolderIcons = (color: string | undefined) => {
293
- if (!color || !validateHEXColorCode(color)) {
294
- return console.error('Invalid color code for folder icons');
295
- }
296
-
297
- const folderIcon =
298
- 'M10 4H4c-1.11 0-2 .89-2 2v12a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V8c0-1.11-.9-2-2-2h-8l-2-2z';
299
- const folderIconOpen =
300
- 'M19 20H4c-1.11 0-2-.9-2-2V6c0-1.11.89-2 2-2h6l2 2h7a2 2 0 0 1 2 2H4v10l2.14-8h17.07l-2.28 8.5c-.23.87-1.01 1.5-1.93 1.5z';
301
- const rootFolderIcon =
302
- 'M12 20a8 8 0 0 1-8-8 8 8 0 0 1 8-8 8 8 0 0 1 8 8 8 8 0 0 1-8 8m0-18A10 10 0 0 0 2 12a10 10 0 0 0 10 10 10 10 0 0 0 10-10A10 10 0 0 0 12 2m0 5a5 5 0 0 0-5 5 5 5 0 0 0 5 5 5 5 0 0 0 5-5 5 5 0 0 0-5-5z';
303
- const rootFolderIconOpen =
304
- 'M12 20a8 8 0 0 1-8-8 8 8 0 0 1 8-8 8 8 0 0 1 8 8 8 8 0 0 1-8 8m0-18A10 10 0 0 0 2 12a10 10 0 0 0 10 10 10 10 0 0 0 10-10A10 10 0 0 0 12 2z';
305
-
306
- writeSVGFiles('folder', getSVG(getPath(folderIcon, color)));
307
- writeSVGFiles('folder-open', getSVG(getPath(folderIconOpen, color)));
308
- writeSVGFiles('folder-root', getSVG(getPath(rootFolderIcon, color)));
309
- writeSVGFiles('folder-root-open', getSVG(getPath(rootFolderIconOpen, color)));
310
- };
311
-
312
- const getPath = (d: string, color: string) =>
313
- `<path d="${d}" fill="${color}" />`;
314
- const getSVG = (path: string) =>
315
- `<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">${path}</svg>`;
316
-
317
- const writeSVGFiles = (iconName: string, svg: string) => {
318
- let iconsPath;
319
- if (path.basename(__dirname) === 'dist') {
320
- iconsPath = path.join(__dirname, '..', 'icons');
321
- } else {
322
- // executed via script
323
- iconsPath = path.join(__dirname, '..', '..', '..', 'icons');
324
- }
325
- const iconsFolderPath = path.join(iconsPath, `${iconName}.svg`);
326
- try {
327
- fs.writeFileSync(iconsFolderPath, svg);
328
- } catch (error) {
329
- console.error(error);
330
- }
331
- };
332
-
333
- /**
334
- * Validate the HEX color code
335
- * @param color HEX code
336
- */
337
- export const validateHEXColorCode = (color: string = '') => {
338
- const hexPattern = new RegExp(/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/);
339
- return color.length > 0 && hexPattern.test(color);
340
- };
1
+ import * as fs from 'fs';
2
+ import merge from 'lodash.merge';
3
+ import * as path from 'path';
4
+ import { getFileConfigHash } from '../../helpers/fileConfig';
5
+ import {
6
+ DefaultIcon,
7
+ FolderIcon,
8
+ FolderTheme,
9
+ IconAssociations,
10
+ IconConfiguration,
11
+ IconJsonOptions,
12
+ } from '../../models/index';
13
+ import {
14
+ highContrastColorFileEnding,
15
+ iconFolderPath,
16
+ lightColorFileEnding,
17
+ openedFolder,
18
+ } from './constants';
19
+
20
+ /**
21
+ * Get the folder icon definitions as object.
22
+ */
23
+ export const loadFolderIconDefinitions = (
24
+ folderThemes: FolderTheme[],
25
+ config: IconConfiguration,
26
+ options: IconJsonOptions
27
+ ): IconConfiguration => {
28
+ config = merge({}, config);
29
+ config.hidesExplorerArrows = options.hidesExplorerArrows;
30
+ const activeTheme = getEnabledFolderTheme(
31
+ folderThemes,
32
+ options.folders?.theme
33
+ );
34
+ if (!activeTheme) {
35
+ return {};
36
+ }
37
+ const enabledIcons = disableIconsByPack(activeTheme, options.activeIconPack);
38
+ const customIcons = getCustomIcons(options.folders?.associations);
39
+ const allIcons = [...enabledIcons, ...customIcons];
40
+
41
+ if (options.folders?.theme === 'none') {
42
+ return config;
43
+ }
44
+
45
+ allIcons.forEach((icon) => {
46
+ if (icon.disabled) return;
47
+ config = setIconDefinitions(config, icon);
48
+ config = merge({}, config, setFolderNames(icon.name, icon.folderNames));
49
+ config.light = icon.light
50
+ ? merge(
51
+ {},
52
+ config.light,
53
+ setFolderNames(icon.name, icon.folderNames, lightColorFileEnding)
54
+ )
55
+ : config.light;
56
+ config.highContrast = icon.highContrast
57
+ ? merge(
58
+ {},
59
+ config.highContrast,
60
+ setFolderNames(
61
+ icon.name,
62
+ icon.folderNames,
63
+ highContrastColorFileEnding
64
+ )
65
+ )
66
+ : config.highContrast;
67
+ });
68
+
69
+ config = setDefaultFolderIcons(activeTheme, config);
70
+ return config;
71
+ };
72
+
73
+ /**
74
+ * Set the default folder icons for the theme.
75
+ */
76
+ const setDefaultFolderIcons = (
77
+ theme: FolderTheme,
78
+ config: IconConfiguration
79
+ ): IconConfiguration => {
80
+ config = merge({}, config);
81
+ const hasFolderIcons =
82
+ !!theme.defaultIcon.name && theme.defaultIcon.name.length > 0;
83
+ if (hasFolderIcons) {
84
+ config = setIconDefinitions(config, theme.defaultIcon);
85
+ }
86
+ config = merge(
87
+ {},
88
+ config,
89
+ createDefaultIconConfigObject(hasFolderIcons, theme, '')
90
+ );
91
+ config.light = theme.defaultIcon.light
92
+ ? merge(
93
+ {},
94
+ config.light,
95
+ createDefaultIconConfigObject(
96
+ hasFolderIcons,
97
+ theme,
98
+ lightColorFileEnding
99
+ )
100
+ )
101
+ : config.light;
102
+ config.highContrast = theme.defaultIcon.highContrast
103
+ ? merge(
104
+ {},
105
+ config.highContrast,
106
+ createDefaultIconConfigObject(
107
+ hasFolderIcons,
108
+ theme,
109
+ highContrastColorFileEnding
110
+ )
111
+ )
112
+ : config.highContrast;
113
+
114
+ config = merge(
115
+ {},
116
+ config,
117
+ createRootIconConfigObject(hasFolderIcons, theme, '')
118
+ );
119
+ if (theme.rootFolder) {
120
+ config = setIconDefinitions(config, theme.rootFolder);
121
+ config.light = theme.rootFolder.light
122
+ ? merge(
123
+ {},
124
+ config.light,
125
+ createRootIconConfigObject(
126
+ hasFolderIcons,
127
+ theme,
128
+ lightColorFileEnding
129
+ )
130
+ )
131
+ : config.light;
132
+ config.highContrast = theme.rootFolder.highContrast
133
+ ? merge(
134
+ {},
135
+ config.highContrast,
136
+ createRootIconConfigObject(
137
+ hasFolderIcons,
138
+ theme,
139
+ highContrastColorFileEnding
140
+ )
141
+ )
142
+ : config.highContrast;
143
+ }
144
+
145
+ return config;
146
+ };
147
+
148
+ /**
149
+ * Get the object of the current enabled theme.
150
+ */
151
+ const getEnabledFolderTheme = (
152
+ themes: FolderTheme[],
153
+ enabledTheme: string | undefined
154
+ ): FolderTheme | undefined => {
155
+ return themes.find((theme) => theme.name === enabledTheme);
156
+ };
157
+
158
+ /**
159
+ * Disable all file icons that are in a pack which is disabled.
160
+ */
161
+ const disableIconsByPack = (
162
+ folderIcons: FolderTheme | undefined,
163
+ activatedIconPack: string | undefined
164
+ ): FolderIcon[] => {
165
+ if (!folderIcons?.icons || folderIcons.icons.length === 0) {
166
+ return [];
167
+ }
168
+ return folderIcons.icons.filter((icon) => {
169
+ return !icon.enabledFor
170
+ ? true
171
+ : icon.enabledFor.some((p) => p === activatedIconPack);
172
+ });
173
+ };
174
+
175
+ const setIconDefinitions = (
176
+ config: IconConfiguration,
177
+ icon: FolderIcon | DefaultIcon
178
+ ) => {
179
+ config = merge({}, config);
180
+ config = createIconDefinitions(config, icon.name);
181
+ if (icon.light) {
182
+ config = merge(
183
+ {},
184
+ config,
185
+ createIconDefinitions(config, icon.name, lightColorFileEnding)
186
+ );
187
+ }
188
+ if (icon.highContrast) {
189
+ config = merge(
190
+ {},
191
+ config,
192
+ createIconDefinitions(config, icon.name, highContrastColorFileEnding)
193
+ );
194
+ }
195
+ return config;
196
+ };
197
+
198
+ const createIconDefinitions = (
199
+ config: IconConfiguration,
200
+ iconName: string,
201
+ appendix: string = ''
202
+ ) => {
203
+ config = merge({}, config);
204
+ const fileConfigHash = getFileConfigHash(config.options ?? {});
205
+ const configIconDefinitions = config.iconDefinitions;
206
+ if (configIconDefinitions) {
207
+ configIconDefinitions[iconName + appendix] = {
208
+ iconPath: `${iconFolderPath}${iconName}${appendix}${fileConfigHash}.svg`,
209
+ };
210
+ configIconDefinitions[`${iconName}${openedFolder}${appendix}`] = {
211
+ iconPath: `${iconFolderPath}${iconName}${openedFolder}${appendix}${fileConfigHash}.svg`,
212
+ };
213
+ }
214
+ return config;
215
+ };
216
+
217
+ const setFolderNames = (
218
+ iconName: string,
219
+ folderNames: string[],
220
+ appendix: string = ''
221
+ ) => {
222
+ const obj: Partial<IconConfiguration> = {
223
+ folderNames: {},
224
+ folderNamesExpanded: {},
225
+ };
226
+ folderNames.forEach((name) => {
227
+ if (obj.folderNames) {
228
+ obj.folderNames[name as keyof IconConfiguration] = iconName + appendix;
229
+ }
230
+ if (obj.folderNamesExpanded) {
231
+ obj.folderNamesExpanded[
232
+ name as keyof IconConfiguration
233
+ ] = `${iconName}${openedFolder}${appendix}`;
234
+ }
235
+ });
236
+ return obj;
237
+ };
238
+
239
+ const createDefaultIconConfigObject = (
240
+ hasFolderIcons: boolean,
241
+ theme: FolderTheme,
242
+ appendix: string = ''
243
+ ) => {
244
+ const obj = {
245
+ folder: '',
246
+ folderExpanded: '',
247
+ };
248
+ obj.folder = hasFolderIcons ? theme.defaultIcon.name + appendix : '';
249
+ obj.folderExpanded = hasFolderIcons
250
+ ? `${theme.defaultIcon.name}${openedFolder}${appendix}`
251
+ : '';
252
+ return obj;
253
+ };
254
+
255
+ const createRootIconConfigObject = (
256
+ hasFolderIcons: boolean,
257
+ theme: FolderTheme,
258
+ appendix: string = ''
259
+ ) => {
260
+ const obj = {
261
+ rootFolder: '',
262
+ rootFolderExpanded: '',
263
+ };
264
+ obj.rootFolder = hasFolderIcons
265
+ ? theme.rootFolder
266
+ ? theme.rootFolder.name + appendix
267
+ : theme.defaultIcon.name + appendix
268
+ : '';
269
+ obj.rootFolderExpanded = hasFolderIcons
270
+ ? theme.rootFolder
271
+ ? `${theme.rootFolder.name}${openedFolder}${appendix}`
272
+ : `${theme.defaultIcon.name}${openedFolder}${appendix}`
273
+ : '';
274
+ return obj;
275
+ };
276
+
277
+ const getCustomIcons = (folderAssociations: IconAssociations | undefined) => {
278
+ if (!folderAssociations) return [];
279
+
280
+ const icons: FolderIcon[] = Object.keys(folderAssociations).map((fa) => ({
281
+ // use default folder if icon name is empty
282
+ name:
283
+ folderAssociations[fa].length > 0
284
+ ? 'folder-' + folderAssociations[fa].toLowerCase()
285
+ : 'folder',
286
+ folderNames: [fa.toLowerCase()],
287
+ }));
288
+
289
+ return icons;
290
+ };
291
+
292
+ export const generateFolderIcons = (color: string | undefined) => {
293
+ if (!color || !validateHEXColorCode(color)) {
294
+ return console.error('Invalid color code for folder icons');
295
+ }
296
+
297
+ const folderIcon =
298
+ 'M10 4H4c-1.11 0-2 .89-2 2v12a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V8c0-1.11-.9-2-2-2h-8l-2-2z';
299
+ const folderIconOpen =
300
+ 'M19 20H4c-1.11 0-2-.9-2-2V6c0-1.11.89-2 2-2h6l2 2h7a2 2 0 0 1 2 2H4v10l2.14-8h17.07l-2.28 8.5c-.23.87-1.01 1.5-1.93 1.5z';
301
+ const rootFolderIcon =
302
+ 'M12 20a8 8 0 0 1-8-8 8 8 0 0 1 8-8 8 8 0 0 1 8 8 8 8 0 0 1-8 8m0-18A10 10 0 0 0 2 12a10 10 0 0 0 10 10 10 10 0 0 0 10-10A10 10 0 0 0 12 2m0 5a5 5 0 0 0-5 5 5 5 0 0 0 5 5 5 5 0 0 0 5-5 5 5 0 0 0-5-5z';
303
+ const rootFolderIconOpen =
304
+ 'M12 20a8 8 0 0 1-8-8 8 8 0 0 1 8-8 8 8 0 0 1 8 8 8 8 0 0 1-8 8m0-18A10 10 0 0 0 2 12a10 10 0 0 0 10 10 10 10 0 0 0 10-10A10 10 0 0 0 12 2z';
305
+
306
+ writeSVGFiles('folder', getSVG(getPath(folderIcon, color)));
307
+ writeSVGFiles('folder-open', getSVG(getPath(folderIconOpen, color)));
308
+ writeSVGFiles('folder-root', getSVG(getPath(rootFolderIcon, color)));
309
+ writeSVGFiles('folder-root-open', getSVG(getPath(rootFolderIconOpen, color)));
310
+ };
311
+
312
+ const getPath = (d: string, color: string) =>
313
+ `<path d="${d}" fill="${color}" />`;
314
+ const getSVG = (path: string) =>
315
+ `<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">${path}</svg>`;
316
+
317
+ const writeSVGFiles = (iconName: string, svg: string) => {
318
+ let iconsPath;
319
+ if (path.basename(__dirname) === 'dist') {
320
+ iconsPath = path.join(__dirname, '..', 'icons');
321
+ } else {
322
+ // executed via script
323
+ iconsPath = path.join(__dirname, '..', '..', '..', 'icons');
324
+ }
325
+ const iconsFolderPath = path.join(iconsPath, `${iconName}.svg`);
326
+ try {
327
+ fs.writeFileSync(iconsFolderPath, svg);
328
+ } catch (error) {
329
+ console.error(error);
330
+ }
331
+ };
332
+
333
+ /**
334
+ * Validate the HEX color code
335
+ * @param color HEX code
336
+ */
337
+ export const validateHEXColorCode = (color: string = '') => {
338
+ const hexPattern = new RegExp(/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/);
339
+ return color.length > 0 && hexPattern.test(color);
340
+ };