material-icon-theme 4.16.0 → 4.18.1

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 (206) 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 +1179 -1135
  15. package/CONTRIBUTING.md +62 -62
  16. package/LICENSE.md +8 -8
  17. package/README.md +208 -209
  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 +5 -0
  22. package/icons/astyle.svg +4 -4
  23. package/icons/auto.svg +10 -0
  24. package/icons/auto_light.svg +10 -0
  25. package/icons/azure.svg +10 -1
  26. package/icons/blitz.svg +4 -4
  27. package/icons/buildkite.svg +9 -1
  28. package/icons/cypress.svg +4 -4
  29. package/icons/dart_generated.svg +9 -0
  30. package/icons/dependabot.svg +4 -4
  31. package/icons/dinophp.svg +16 -16
  32. package/icons/figma.svg +10 -10
  33. package/icons/folder-angular-open.svg +2 -2
  34. package/icons/folder-angular.svg +2 -2
  35. package/icons/folder-buildkite-open.svg +9 -0
  36. package/icons/folder-buildkite.svg +8 -0
  37. package/icons/folder-cypress-open.svg +5 -5
  38. package/icons/folder-cypress.svg +5 -5
  39. package/icons/folder-java-open.svg +2 -2
  40. package/icons/folder-java.svg +2 -2
  41. package/icons/folder-lua-open.svg +1 -0
  42. package/icons/folder-lua.svg +1 -0
  43. package/icons/folder-next-open.svg +2 -2
  44. package/icons/folder-next.svg +2 -2
  45. package/icons/folder-nuxt-open.svg +2 -1
  46. package/icons/folder-nuxt.svg +2 -1
  47. package/icons/folder-queue-open.svg +2 -2
  48. package/icons/folder-queue.svg +2 -2
  49. package/icons/folder-resolver-open.svg +2 -2
  50. package/icons/folder-resolver.svg +2 -2
  51. package/icons/folder-serverless-open.svg +5 -5
  52. package/icons/folder-serverless.svg +5 -5
  53. package/icons/folder-shader-open.svg +8 -0
  54. package/icons/folder-shader.svg +7 -0
  55. package/icons/folder-target-open.svg +2 -2
  56. package/icons/folder-target.svg +2 -2
  57. package/icons/folder-unity-open.svg +2 -2
  58. package/icons/folder-unity.svg +2 -2
  59. package/icons/folder-vercel-open.svg +4 -4
  60. package/icons/folder-vercel.svg +4 -4
  61. package/icons/folder-verdaccio-open.svg +8 -0
  62. package/icons/folder-verdaccio.svg +8 -0
  63. package/icons/gleam.svg +4 -4
  64. package/icons/gridsome.svg +4 -4
  65. package/icons/hardhat.svg +3 -3
  66. package/icons/lighthouse.svg +2 -2
  67. package/icons/ndst.svg +7 -7
  68. package/icons/next.svg +3 -3
  69. package/icons/next_light.svg +2 -2
  70. package/icons/nuxt.svg +5 -1
  71. package/icons/odin.svg +6 -6
  72. package/icons/otne.svg +16 -0
  73. package/icons/parcel.svg +4 -4
  74. package/icons/playwright.svg +7 -7
  75. package/icons/plop.svg +4 -0
  76. package/icons/pnpm.svg +9 -9
  77. package/icons/pnpm_light.svg +7 -7
  78. package/icons/poetry.svg +1 -1
  79. package/icons/processing.svg +10 -10
  80. package/icons/remix.svg +4 -4
  81. package/icons/remix_light.svg +4 -4
  82. package/icons/rescript-interface.svg +5 -0
  83. package/icons/rome.svg +5 -5
  84. package/icons/serverless.svg +4 -4
  85. package/icons/shader.svg +4 -0
  86. package/icons/siyuan.svg +9 -9
  87. package/icons/steadybit.svg +1 -1
  88. package/icons/svgr.svg +4 -4
  89. package/icons/tauri.svg +9 -9
  90. package/icons/template.svg +4 -4
  91. package/icons/tobi.svg +4 -4
  92. package/icons/tobimake.svg +14 -14
  93. package/icons/turborepo.svg +12 -12
  94. package/icons/turborepo_light.svg +12 -12
  95. package/icons/verdaccio.svg +5 -0
  96. package/images/contributors.png +0 -0
  97. package/images/fileIcons.png +0 -0
  98. package/images/folderIcons.png +0 -0
  99. package/logo.svg +21 -21
  100. package/material-colors.yml +257 -257
  101. package/package.json +267 -264
  102. package/package.nls.de.json +35 -35
  103. package/package.nls.es.json +32 -32
  104. package/package.nls.fr.json +32 -32
  105. package/package.nls.ja.json +35 -35
  106. package/package.nls.json +35 -35
  107. package/package.nls.nl.json +35 -35
  108. package/package.nls.pl.json +35 -35
  109. package/package.nls.pt-BR.json +32 -32
  110. package/package.nls.pt-PT.json +32 -32
  111. package/package.nls.ru.json +32 -32
  112. package/package.nls.zh-CN.json +32 -32
  113. package/package.nls.zh-TW.json +32 -32
  114. package/src/commands/activate.ts +26 -26
  115. package/src/commands/explorerArrows.ts +55 -55
  116. package/src/commands/folderColor.ts +96 -96
  117. package/src/commands/folders.ts +55 -55
  118. package/src/commands/grayscale.ts +55 -55
  119. package/src/commands/iconPacks.ts +68 -68
  120. package/src/commands/index.ts +30 -30
  121. package/src/commands/opacity.ts +46 -46
  122. package/src/commands/restoreConfig.ts +14 -14
  123. package/src/commands/saturation.ts +46 -46
  124. package/src/extension.ts +42 -35
  125. package/src/helpers/changeDetection.ts +105 -68
  126. package/src/helpers/customIcons.ts +8 -8
  127. package/src/helpers/fileConfig.ts +37 -37
  128. package/src/helpers/index.ts +100 -100
  129. package/src/helpers/objects.ts +58 -58
  130. package/src/helpers/types.ts +7 -7
  131. package/src/helpers/versioning.ts +73 -73
  132. package/src/i18n/index.ts +78 -78
  133. package/src/i18n/lang-de.ts +54 -54
  134. package/src/i18n/lang-en.ts +53 -53
  135. package/src/i18n/lang-es.ts +53 -53
  136. package/src/i18n/lang-fr.ts +53 -53
  137. package/src/i18n/lang-ja.ts +54 -54
  138. package/src/i18n/lang-nl.ts +54 -54
  139. package/src/i18n/lang-pl.ts +52 -52
  140. package/src/i18n/lang-pt-br.ts +53 -53
  141. package/src/i18n/lang-pt-pt.ts +53 -53
  142. package/src/i18n/lang-ru.ts +52 -52
  143. package/src/i18n/lang-uk.ts +54 -54
  144. package/src/i18n/lang-zh-cn.ts +52 -52
  145. package/src/i18n/lang-zh-tw.ts +52 -52
  146. package/src/icons/fileIcons.ts +2060 -1854
  147. package/src/icons/folderIcons.ts +773 -754
  148. package/src/icons/generator/constants.ts +29 -29
  149. package/src/icons/generator/fileGenerator.ts +216 -216
  150. package/src/icons/generator/folderGenerator.ts +340 -340
  151. package/src/icons/generator/iconOpacity.ts +111 -111
  152. package/src/icons/generator/iconSaturation.ts +140 -140
  153. package/src/icons/generator/index.ts +7 -7
  154. package/src/icons/generator/jsonGenerator.ts +187 -187
  155. package/src/icons/generator/languageGenerator.ts +127 -127
  156. package/src/icons/index.ts +4 -4
  157. package/src/icons/languageIcons.ts +136 -134
  158. package/src/messages/outdated.ts +33 -33
  159. package/src/messages/reload.ts +32 -32
  160. package/src/messages/start.ts +12 -12
  161. package/src/messages/update.ts +48 -48
  162. package/src/messages/welcome.ts +47 -47
  163. package/src/models/helpers/index.ts +1 -1
  164. package/src/models/helpers/themeStatus.ts +5 -5
  165. package/src/models/i18n/index.ts +1 -1
  166. package/src/models/i18n/translation.ts +50 -50
  167. package/src/models/iconConfiguration.ts +37 -37
  168. package/src/models/icons/defaultIcon.ts +16 -16
  169. package/src/models/icons/files/fileIcon.ts +49 -49
  170. package/src/models/icons/files/fileTypes.ts +14 -14
  171. package/src/models/icons/files/index.ts +2 -2
  172. package/src/models/icons/folders/folderIcon.ts +34 -34
  173. package/src/models/icons/folders/folderTheme.ts +23 -23
  174. package/src/models/icons/folders/index.ts +2 -2
  175. package/src/models/icons/iconJsonOptions.ts +23 -23
  176. package/src/models/icons/iconPack.ts +12 -12
  177. package/src/models/icons/index.ts +6 -6
  178. package/src/models/icons/languages/index.ts +1 -1
  179. package/src/models/icons/languages/languageIdentifier.ts +26 -26
  180. package/src/models/index.ts +4 -4
  181. package/src/models/scripts/contributors/contributor.ts +22 -22
  182. package/src/models/scripts/contributors/contributorsConfig.ts +10 -10
  183. package/src/scripts/contributors/contributors.css +24 -24
  184. package/src/scripts/contributors/index.ts +138 -138
  185. package/src/scripts/helpers/painter.ts +5 -5
  186. package/src/scripts/helpers/screenshots.ts +32 -32
  187. package/src/scripts/helpers/similarity.ts +47 -47
  188. package/src/scripts/helpers/titleCase.ts +7 -7
  189. package/src/scripts/icons/checks/checkIconAvailability.ts +215 -215
  190. package/src/scripts/icons/checks/checkIconConflicts.ts +154 -154
  191. package/src/scripts/icons/checks/checkIconUsage.ts +141 -141
  192. package/src/scripts/icons/checks/index.ts +7 -7
  193. package/src/scripts/icons/generateJson.ts +11 -11
  194. package/src/scripts/preview/index.ts +40 -40
  195. package/src/scripts/preview/preview.ts +165 -165
  196. package/src/scripts/preview/style.css +48 -48
  197. package/src/test/runTest.ts +26 -26
  198. package/src/test/spec/i18n/i18n.spec.ts +61 -61
  199. package/src/test/spec/icons/fileIcons.spec.ts +250 -250
  200. package/src/test/spec/icons/folderIcons.spec.ts +418 -418
  201. package/src/test/spec/icons/languageIcons.spec.ts +184 -184
  202. package/src/test/spec/index.ts +36 -36
  203. package/src/web/extension.ts +10 -10
  204. package/svgo.config.js +11 -11
  205. package/tsconfig.json +23 -23
  206. package/icons/nuxt_light.svg +0 -1
@@ -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
+ };