@nice2dev/icons 1.3.15 → 1.3.17

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 (153) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/README.md +1 -1
  3. package/dist/cjs/NiceDesktopIconExporter.js +688 -599
  4. package/dist/cjs/NiceFaviconGenerator.js +603 -417
  5. package/dist/cjs/NiceIconPicker.js +788 -508
  6. package/dist/cjs/NiceIconPreview.js +246 -188
  7. package/dist/cjs/NiceIconSetCreator.js +683 -552
  8. package/dist/cjs/NiceIconStacker.js +547 -171
  9. package/dist/cjs/NiceIconValue.js +27 -35
  10. package/dist/cjs/NtdIconBadge.js +384 -360
  11. package/dist/cjs/NtdIconMorph.js +419 -354
  12. package/dist/cjs/NtdStateMorph.js +150 -147
  13. package/dist/cjs/advancedIconSearch.js +373 -510
  14. package/dist/cjs/animationControls.js +518 -642
  15. package/dist/cjs/animationSpeed.js +69 -0
  16. package/dist/cjs/client.js +12 -15
  17. package/dist/cjs/createIcon.js +374 -252
  18. package/dist/cjs/design-tokens.js +324 -390
  19. package/dist/cjs/figmaExport.js +162 -257
  20. package/dist/cjs/figmaSync.js +234 -316
  21. package/dist/cjs/headless-ui.js +240 -368
  22. package/dist/cjs/iconAnalytics.js +337 -393
  23. package/dist/cjs/iconHtml.js +64 -86
  24. package/dist/cjs/iconMetadata.js +392 -472
  25. package/dist/cjs/iconParts.js +120 -90
  26. package/dist/cjs/iconStack.js +136 -155
  27. package/dist/cjs/iconStyles.js +1670 -509
  28. package/dist/cjs/iconValue.js +359 -430
  29. package/dist/cjs/icons/accessibility.js +1119 -134
  30. package/dist/cjs/icons/actions.js +1290 -330
  31. package/dist/cjs/icons/ai.js +1424 -144
  32. package/dist/cjs/icons/brand.js +613 -184
  33. package/dist/cjs/icons/business.js +938 -192
  34. package/dist/cjs/icons/devtech.js +1656 -227
  35. package/dist/cjs/icons/ecommerce.js +802 -111
  36. package/dist/cjs/icons/education.js +1345 -199
  37. package/dist/cjs/icons/files.js +1597 -328
  38. package/dist/cjs/icons/fintech.js +793 -104
  39. package/dist/cjs/icons/food.js +1028 -156
  40. package/dist/cjs/icons/fun.js +804 -109
  41. package/dist/cjs/icons/gaming.js +916 -170
  42. package/dist/cjs/icons/health.js +623 -112
  43. package/dist/cjs/icons/index.js +32 -42
  44. package/dist/cjs/icons/input.js +282 -83
  45. package/dist/cjs/icons/legal.js +1065 -122
  46. package/dist/cjs/icons/media.js +1061 -267
  47. package/dist/cjs/icons/navigation.js +407 -123
  48. package/dist/cjs/icons/omniverk.js +523 -93
  49. package/dist/cjs/icons/realestate.js +1520 -193
  50. package/dist/cjs/icons/saas.js +867 -98
  51. package/dist/cjs/icons/science.js +1344 -202
  52. package/dist/cjs/icons/shapes.js +1316 -308
  53. package/dist/cjs/icons/smarthome.js +786 -90
  54. package/dist/cjs/icons/social.js +591 -59
  55. package/dist/cjs/icons/sports.js +1133 -133
  56. package/dist/cjs/icons/sustainability.js +1211 -139
  57. package/dist/cjs/icons/travel.js +1470 -148
  58. package/dist/cjs/icons/ui.js +1508 -315
  59. package/dist/cjs/icons/weather.js +1160 -173
  60. package/dist/cjs/index.js +559 -568
  61. package/dist/cjs/lottieIntegration.js +261 -266
  62. package/dist/cjs/nicetodev-icons.css +1 -1
  63. package/dist/cjs/particleEffects.js +270 -251
  64. package/dist/cjs/resolver.js +229 -284
  65. package/dist/cjs/rsc.js +175 -193
  66. package/dist/cjs/sharpen.js +73 -130
  67. package/dist/cjs/smilAnimations.js +380 -165
  68. package/dist/cjs/stacking.js +87 -122
  69. package/dist/cjs/tailwind-plugin.js +280 -320
  70. package/dist/cjs/types.js +46 -72
  71. package/dist/cjs/utilities.js +163 -324
  72. package/dist/cjs/variantProps.js +12 -52
  73. package/dist/esm/NiceDesktopIconExporter.js +671 -598
  74. package/dist/esm/NiceFaviconGenerator.js +583 -416
  75. package/dist/esm/NiceIconPicker.js +789 -507
  76. package/dist/esm/NiceIconPreview.js +247 -187
  77. package/dist/esm/NiceIconSetCreator.js +685 -551
  78. package/dist/esm/NiceIconStacker.js +549 -170
  79. package/dist/esm/NiceIconValue.js +29 -34
  80. package/dist/esm/NtdIconBadge.js +388 -359
  81. package/dist/esm/NtdIconMorph.js +423 -353
  82. package/dist/esm/NtdStateMorph.js +152 -146
  83. package/dist/esm/advancedIconSearch.js +391 -509
  84. package/dist/esm/animationControls.js +527 -641
  85. package/dist/esm/animationSpeed.js +69 -0
  86. package/dist/esm/client.js +48 -10
  87. package/dist/esm/createIcon.js +375 -251
  88. package/dist/esm/design-tokens.js +334 -387
  89. package/dist/esm/figmaExport.js +170 -256
  90. package/dist/esm/figmaSync.js +237 -315
  91. package/dist/esm/headless-ui.js +254 -365
  92. package/dist/esm/iconAnalytics.js +342 -392
  93. package/dist/esm/iconHtml.js +67 -85
  94. package/dist/esm/iconMetadata.js +404 -471
  95. package/dist/esm/iconParts.js +125 -89
  96. package/dist/esm/iconStack.js +145 -154
  97. package/dist/esm/iconStyles.js +1681 -508
  98. package/dist/esm/iconValue.js +361 -429
  99. package/dist/esm/icons/accessibility.js +1133 -133
  100. package/dist/esm/icons/actions.js +1320 -329
  101. package/dist/esm/icons/ai.js +1441 -143
  102. package/dist/esm/icons/brand.js +616 -179
  103. package/dist/esm/icons/business.js +957 -191
  104. package/dist/esm/icons/devtech.js +1687 -226
  105. package/dist/esm/icons/ecommerce.js +816 -110
  106. package/dist/esm/icons/education.js +1364 -198
  107. package/dist/esm/icons/files.js +1628 -327
  108. package/dist/esm/icons/fintech.js +807 -103
  109. package/dist/esm/icons/food.js +1043 -153
  110. package/dist/esm/icons/fun.js +819 -108
  111. package/dist/esm/icons/gaming.js +933 -169
  112. package/dist/esm/icons/health.js +636 -111
  113. package/dist/esm/icons/index.js +589 -32
  114. package/dist/esm/icons/input.js +326 -82
  115. package/dist/esm/icons/legal.js +1079 -121
  116. package/dist/esm/icons/media.js +1086 -266
  117. package/dist/esm/icons/navigation.js +421 -122
  118. package/dist/esm/icons/omniverk.js +534 -91
  119. package/dist/esm/icons/realestate.js +1544 -198
  120. package/dist/esm/icons/saas.js +880 -97
  121. package/dist/esm/icons/science.js +1370 -208
  122. package/dist/esm/icons/shapes.js +1343 -307
  123. package/dist/esm/icons/smarthome.js +799 -89
  124. package/dist/esm/icons/social.js +599 -58
  125. package/dist/esm/icons/sports.js +1148 -132
  126. package/dist/esm/icons/sustainability.js +1226 -138
  127. package/dist/esm/icons/travel.js +1486 -147
  128. package/dist/esm/icons/ui.js +1540 -314
  129. package/dist/esm/icons/weather.js +1181 -172
  130. package/dist/esm/index.js +749 -58
  131. package/dist/esm/lottieIntegration.js +264 -265
  132. package/dist/esm/nicetodev-icons.css +1 -1
  133. package/dist/esm/particleEffects.js +271 -250
  134. package/dist/esm/resolver.js +231 -283
  135. package/dist/esm/rsc.js +182 -192
  136. package/dist/esm/sharpen.js +78 -129
  137. package/dist/esm/smilAnimations.js +385 -164
  138. package/dist/esm/stacking.js +99 -121
  139. package/dist/esm/tailwind-plugin.js +282 -319
  140. package/dist/esm/types.js +50 -71
  141. package/dist/esm/utilities.js +177 -321
  142. package/dist/esm/variantProps.js +23 -52
  143. package/dist/types/animationSpeed.d.ts +19 -0
  144. package/dist/types/createIcon.d.ts +6 -0
  145. package/dist/types/iconStyles.d.ts +6 -1
  146. package/dist/types/icons/brand.d.ts +0 -4
  147. package/dist/types/icons/food.d.ts +0 -3
  148. package/dist/types/icons/index.d.ts +3 -3
  149. package/dist/types/icons/omniverk.d.ts +0 -3
  150. package/dist/types/icons/science.d.ts +1 -1
  151. package/dist/types/smilAnimations.d.ts +4 -2
  152. package/dist/types/types.d.ts +7 -0
  153. package/package.json +15 -22
@@ -1,430 +1,597 @@
1
- import { jsxs, jsx } from 'react/jsx-runtime';
2
- import { useNiceTranslation } from '@nice2dev/ui-core';
3
- import { useState, useCallback } from 'react';
4
- import { NtdDownload } from './icons/actions.js';
5
-
6
- /* ══════════════════════════════════════════════════════════════════════════════
7
- Constants
8
- ══════════════════════════════════════════════════════════════════════════════ */
1
+ import { jsxs, jsx } from "react/jsx-runtime";
2
+ import { useNiceTranslation } from "@nice2dev/ui-core";
3
+ import { useState, useCallback } from "react";
4
+ import { NtdDownload } from "./icons/actions.js";
9
5
  const FAVICON_SIZES = [
10
- { name: 'favicon-16x16', size: 16, purpose: 'Browser tab', format: 'png' },
11
- { name: 'favicon-32x32', size: 32, purpose: 'Browser tab (Retina)', format: 'png' },
12
- { name: 'favicon-48x48', size: 48, purpose: 'Windows site icon', format: 'png' },
13
- { name: 'favicon', size: 32, purpose: 'Legacy ICO format', format: 'ico' },
14
- { name: 'apple-touch-icon', size: 180, purpose: 'iOS home screen', format: 'png' },
15
- { name: 'android-chrome-192x192', size: 192, purpose: 'Android Chrome', format: 'png' },
16
- { name: 'android-chrome-512x512', size: 512, purpose: 'Android splash', format: 'png' },
17
- { name: 'mstile-150x150', size: 150, purpose: 'Windows tile', format: 'png' },
18
- { name: 'safari-pinned-tab', size: 512, purpose: 'Safari pinned tab', format: 'svg' },
6
+ { name: "favicon-16x16", size: 16, purpose: "Browser tab", format: "png" },
7
+ { name: "favicon-32x32", size: 32, purpose: "Browser tab (Retina)", format: "png" },
8
+ { name: "favicon-48x48", size: 48, purpose: "Windows site icon", format: "png" },
9
+ { name: "favicon", size: 32, purpose: "Legacy ICO format", format: "ico" },
10
+ { name: "apple-touch-icon", size: 180, purpose: "iOS home screen", format: "png" },
11
+ { name: "android-chrome-192x192", size: 192, purpose: "Android Chrome", format: "png" },
12
+ { name: "android-chrome-512x512", size: 512, purpose: "Android splash", format: "png" },
13
+ { name: "mstile-150x150", size: 150, purpose: "Windows tile", format: "png" },
14
+ { name: "safari-pinned-tab", size: 512, purpose: "Safari pinned tab", format: "svg" }
19
15
  ];
20
16
  const DEFAULT_MANIFEST = {
21
- name: 'My Application',
22
- shortName: 'MyApp',
23
- description: '',
24
- themeColor: '#ffffff',
25
- backgroundColor: '#ffffff',
26
- display: 'standalone',
27
- startUrl: '/',
17
+ name: "My Application",
18
+ shortName: "MyApp",
19
+ description: "",
20
+ themeColor: "#ffffff",
21
+ backgroundColor: "#ffffff",
22
+ display: "standalone",
23
+ startUrl: "/"
28
24
  };
29
- function useFaviconGenerator(icon, fill = '#1e1e1e', initialConfig) {
30
- const [config, setConfig] = useState({
31
- ...DEFAULT_MANIFEST,
32
- ...initialConfig,
33
- });
34
- const [assets, setAssets] = useState([]);
35
- const [isGenerating, setIsGenerating] = useState(false);
36
- // Render icon to canvas
37
- const renderToCanvas = useCallback(async (size) => {
38
- const canvas = document.createElement('canvas');
39
- canvas.width = size;
40
- canvas.height = size;
41
- const ctx = canvas.getContext('2d');
42
- // Create SVG from icon
43
- const svgContainer = document.createElement('div');
44
- const IconComponent = icon;
45
- // Render to get SVG string
46
- const { createRoot } = await import('react-dom/client');
47
- const root = createRoot(svgContainer);
48
- return new Promise((resolve) => {
49
- root.render(jsx(IconComponent, { size: size * 0.8, fill: fill }));
25
+ function useFaviconGenerator(icon, fill = "#1e1e1e", initialConfig) {
26
+ const [config, setConfig] = useState({
27
+ ...DEFAULT_MANIFEST,
28
+ ...initialConfig
29
+ });
30
+ const [assets, setAssets] = useState([]);
31
+ const [isGenerating, setIsGenerating] = useState(false);
32
+ const renderToCanvas = useCallback(
33
+ async (size) => {
34
+ const canvas = document.createElement("canvas");
35
+ canvas.width = size;
36
+ canvas.height = size;
37
+ const ctx = canvas.getContext("2d");
38
+ const svgContainer = document.createElement("div");
39
+ const IconComponent = icon;
40
+ const { createRoot } = await import("react-dom/client");
41
+ const root = createRoot(svgContainer);
42
+ return new Promise((resolve) => {
43
+ root.render(/* @__PURE__ */ jsx(IconComponent, { size: size * 0.8, fill }));
44
+ setTimeout(() => {
45
+ const svg = svgContainer.querySelector("svg");
46
+ if (svg) {
47
+ const padding = size * 0.1;
48
+ ctx.fillStyle = config.backgroundColor;
49
+ ctx.fillRect(0, 0, size, size);
50
+ const svgData = new XMLSerializer().serializeToString(svg);
51
+ const img = new Image();
52
+ img.onload = () => {
53
+ ctx.drawImage(img, padding, padding, size * 0.8, size * 0.8);
54
+ root.unmount();
55
+ resolve(canvas);
56
+ };
57
+ img.src = "data:image/svg+xml;base64," + btoa(unescape(encodeURIComponent(svgData)));
58
+ } else {
59
+ root.unmount();
60
+ resolve(canvas);
61
+ }
62
+ }, 50);
63
+ });
64
+ },
65
+ [icon, fill, config.backgroundColor]
66
+ );
67
+ const generate = useCallback(async () => {
68
+ setIsGenerating(true);
69
+ const generated = [];
70
+ try {
71
+ for (const faviconSize of FAVICON_SIZES) {
72
+ if (faviconSize.format === "svg") {
73
+ const svgContainer = document.createElement("div");
74
+ const { createRoot } = await import("react-dom/client");
75
+ const root = createRoot(svgContainer);
76
+ const IconComponent = icon;
77
+ await new Promise((resolve) => {
78
+ root.render(/* @__PURE__ */ jsx(IconComponent, { size: faviconSize.size, fill }));
50
79
  setTimeout(() => {
51
- const svg = svgContainer.querySelector('svg');
52
- if (svg) {
53
- // Center icon
54
- const padding = size * 0.1;
55
- ctx.fillStyle = config.backgroundColor;
56
- ctx.fillRect(0, 0, size, size);
57
- const svgData = new XMLSerializer().serializeToString(svg);
58
- const img = new Image();
59
- img.onload = () => {
60
- ctx.drawImage(img, padding, padding, size * 0.8, size * 0.8);
61
- root.unmount();
62
- resolve(canvas);
63
- };
64
- img.src = 'data:image/svg+xml;base64,' + btoa(unescape(encodeURIComponent(svgData)));
65
- }
66
- else {
67
- root.unmount();
68
- resolve(canvas);
69
- }
80
+ const svg = svgContainer.querySelector("svg");
81
+ if (svg) {
82
+ const svgData = new XMLSerializer().serializeToString(svg);
83
+ generated.push({
84
+ filename: `${faviconSize.name}.svg`,
85
+ size: faviconSize.size,
86
+ purpose: faviconSize.purpose,
87
+ dataUrl: "data:image/svg+xml;base64," + btoa(unescape(encodeURIComponent(svgData)))
88
+ });
89
+ }
90
+ root.unmount();
91
+ resolve();
70
92
  }, 50);
71
- });
72
- }, [icon, fill, config.backgroundColor]);
73
- // Generate all assets
74
- const generate = useCallback(async () => {
75
- setIsGenerating(true);
76
- const generated = [];
77
- try {
78
- for (const faviconSize of FAVICON_SIZES) {
79
- if (faviconSize.format === 'svg') {
80
- // SVG format
81
- const svgContainer = document.createElement('div');
82
- const { createRoot } = await import('react-dom/client');
83
- const root = createRoot(svgContainer);
84
- const IconComponent = icon;
85
- await new Promise((resolve) => {
86
- root.render(jsx(IconComponent, { size: faviconSize.size, fill: fill }));
87
- setTimeout(() => {
88
- const svg = svgContainer.querySelector('svg');
89
- if (svg) {
90
- const svgData = new XMLSerializer().serializeToString(svg);
91
- generated.push({
92
- filename: `${faviconSize.name}.svg`,
93
- size: faviconSize.size,
94
- purpose: faviconSize.purpose,
95
- dataUrl: 'data:image/svg+xml;base64,' + btoa(unescape(encodeURIComponent(svgData))),
96
- });
97
- }
98
- root.unmount();
99
- resolve();
100
- }, 50);
101
- });
102
- }
103
- else {
104
- // PNG/ICO format
105
- const canvas = await renderToCanvas(faviconSize.size);
106
- const dataUrl = canvas.toDataURL('image/png');
107
- generated.push({
108
- filename: `${faviconSize.name}.${faviconSize.format === 'ico' ? 'ico' : 'png'}`,
109
- size: faviconSize.size,
110
- purpose: faviconSize.purpose,
111
- dataUrl,
112
- });
113
- }
114
- }
115
- setAssets(generated);
93
+ });
94
+ } else {
95
+ const canvas = await renderToCanvas(faviconSize.size);
96
+ const dataUrl = canvas.toDataURL("image/png");
97
+ generated.push({
98
+ filename: `${faviconSize.name}.${faviconSize.format === "ico" ? "ico" : "png"}`,
99
+ size: faviconSize.size,
100
+ purpose: faviconSize.purpose,
101
+ dataUrl
102
+ });
116
103
  }
117
- catch (error) {
118
- console.error('Failed to generate favicons:', error);
104
+ }
105
+ setAssets(generated);
106
+ } catch (error) {
107
+ console.error("Failed to generate favicons:", error);
108
+ } finally {
109
+ setIsGenerating(false);
110
+ }
111
+ }, [icon, fill, renderToCanvas]);
112
+ const getManifestJson = useCallback(() => {
113
+ const manifest = {
114
+ name: config.name,
115
+ short_name: config.shortName,
116
+ description: config.description || void 0,
117
+ theme_color: config.themeColor,
118
+ background_color: config.backgroundColor,
119
+ display: config.display,
120
+ start_url: config.startUrl,
121
+ icons: [
122
+ {
123
+ src: "/android-chrome-192x192.png",
124
+ sizes: "192x192",
125
+ type: "image/png"
126
+ },
127
+ {
128
+ src: "/android-chrome-512x512.png",
129
+ sizes: "512x512",
130
+ type: "image/png"
131
+ },
132
+ {
133
+ src: "/android-chrome-512x512.png",
134
+ sizes: "512x512",
135
+ type: "image/png",
136
+ purpose: "maskable"
119
137
  }
120
- finally {
121
- setIsGenerating(false);
122
- }
123
- }, [icon, fill, renderToCanvas]);
124
- // Get manifest.json content
125
- const getManifestJson = useCallback(() => {
126
- const manifest = {
127
- name: config.name,
128
- short_name: config.shortName,
129
- description: config.description || undefined,
130
- theme_color: config.themeColor,
131
- background_color: config.backgroundColor,
132
- display: config.display,
133
- start_url: config.startUrl,
134
- icons: [
135
- {
136
- src: '/android-chrome-192x192.png',
137
- sizes: '192x192',
138
- type: 'image/png',
139
- },
140
- {
141
- src: '/android-chrome-512x512.png',
142
- sizes: '512x512',
143
- type: 'image/png',
144
- },
145
- {
146
- src: '/android-chrome-512x512.png',
147
- sizes: '512x512',
148
- type: 'image/png',
149
- purpose: 'maskable',
150
- },
151
- ],
152
- };
153
- return JSON.stringify(manifest, null, 2);
154
- }, [config]);
155
- // Get HTML tags for linking favicons
156
- const getHtmlTags = useCallback(() => {
157
- return `<!-- Favicons -->
158
- <link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
159
- <link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
160
- <link rel="shortcut icon" href="/favicon.ico">
161
-
162
- <!-- Apple Touch Icon -->
163
- <link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
164
-
165
- <!-- Safari Pinned Tab -->
166
- <link rel="mask-icon" href="/safari-pinned-tab.svg" color="${config.themeColor}">
167
-
168
- <!-- Windows -->
169
- <meta name="msapplication-TileColor" content="${config.backgroundColor}">
170
- <meta name="msapplication-TileImage" content="/mstile-150x150.png">
171
-
172
- <!-- Theme -->
173
- <meta name="theme-color" content="${config.themeColor}">
174
-
175
- <!-- Web App Manifest -->
176
- <link rel="manifest" href="/manifest.json">`;
177
- }, [config]);
178
- // Download single asset
179
- const downloadSingle = useCallback((asset) => {
180
- const link = document.createElement('a');
181
- link.href = asset.dataUrl;
182
- link.download = asset.filename;
183
- link.click();
184
- }, []);
185
- // Download all as ZIP (simplified - downloads individually)
186
- const downloadAll = useCallback(() => {
187
- // Download manifest
188
- const manifestBlob = new Blob([getManifestJson()], { type: 'application/json' });
189
- const manifestUrl = URL.createObjectURL(manifestBlob);
190
- const manifestLink = document.createElement('a');
191
- manifestLink.href = manifestUrl;
192
- manifestLink.download = 'manifest.json';
193
- manifestLink.click();
194
- URL.revokeObjectURL(manifestUrl);
195
- // Download HTML tags
196
- const htmlBlob = new Blob([getHtmlTags()], { type: 'text/html' });
197
- const htmlUrl = URL.createObjectURL(htmlBlob);
198
- const htmlLink = document.createElement('a');
199
- htmlLink.href = htmlUrl;
200
- htmlLink.download = 'favicon-tags.html';
201
- htmlLink.click();
202
- URL.revokeObjectURL(htmlUrl);
203
- // Download assets
204
- assets.forEach((asset, i) => {
205
- setTimeout(() => downloadSingle(asset), i * 200);
206
- });
207
- }, [assets, downloadSingle, getManifestJson, getHtmlTags]);
208
- return {
209
- config,
210
- setConfig,
211
- assets,
212
- isGenerating,
213
- generate,
214
- downloadAll,
215
- downloadSingle,
216
- getManifestJson,
217
- getHtmlTags,
138
+ ]
218
139
  };
140
+ return JSON.stringify(manifest, null, 2);
141
+ }, [config]);
142
+ const getHtmlTags = useCallback(() => {
143
+ return `<!-- Favicons -->
144
+ <link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
145
+ <link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
146
+ <link rel="shortcut icon" href="/favicon.ico">
147
+
148
+ <!-- Apple Touch Icon -->
149
+ <link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
150
+
151
+ <!-- Safari Pinned Tab -->
152
+ <link rel="mask-icon" href="/safari-pinned-tab.svg" color="${config.themeColor}">
153
+
154
+ <!-- Windows -->
155
+ <meta name="msapplication-TileColor" content="${config.backgroundColor}">
156
+ <meta name="msapplication-TileImage" content="/mstile-150x150.png">
157
+
158
+ <!-- Theme -->
159
+ <meta name="theme-color" content="${config.themeColor}">
160
+
161
+ <!-- Web App Manifest -->
162
+ <link rel="manifest" href="/manifest.json">`;
163
+ }, [config]);
164
+ const downloadSingle = useCallback((asset) => {
165
+ const link = document.createElement("a");
166
+ link.href = asset.dataUrl;
167
+ link.download = asset.filename;
168
+ link.click();
169
+ }, []);
170
+ const downloadAll = useCallback(() => {
171
+ const manifestBlob = new Blob([getManifestJson()], { type: "application/json" });
172
+ const manifestUrl = URL.createObjectURL(manifestBlob);
173
+ const manifestLink = document.createElement("a");
174
+ manifestLink.href = manifestUrl;
175
+ manifestLink.download = "manifest.json";
176
+ manifestLink.click();
177
+ URL.revokeObjectURL(manifestUrl);
178
+ const htmlBlob = new Blob([getHtmlTags()], { type: "text/html" });
179
+ const htmlUrl = URL.createObjectURL(htmlBlob);
180
+ const htmlLink = document.createElement("a");
181
+ htmlLink.href = htmlUrl;
182
+ htmlLink.download = "favicon-tags.html";
183
+ htmlLink.click();
184
+ URL.revokeObjectURL(htmlUrl);
185
+ assets.forEach((asset, i) => {
186
+ setTimeout(() => downloadSingle(asset), i * 200);
187
+ });
188
+ }, [assets, downloadSingle, getManifestJson, getHtmlTags]);
189
+ return {
190
+ config,
191
+ setConfig,
192
+ assets,
193
+ isGenerating,
194
+ generate,
195
+ downloadAll,
196
+ downloadSingle,
197
+ getManifestJson,
198
+ getHtmlTags
199
+ };
219
200
  }
220
- /* ══════════════════════════════════════════════════════════════════════════════
221
- Component
222
- ══════════════════════════════════════════════════════════════════════════════ */
223
- /**
224
- * Favicon generator component for creating all favicon variants.
225
- */
226
- function NiceFaviconGenerator({ icon, fill = '#1e1e1e', manifestConfig, onGenerate, className = '', }) {
227
- const { t } = useNiceTranslation();
228
- const { config, setConfig, assets, isGenerating, generate, downloadAll, downloadSingle, getManifestJson, getHtmlTags, } = useFaviconGenerator(icon, fill, manifestConfig);
229
- const [activeTab, setActiveTab] = useState('preview');
230
- const handleGenerate = async () => {
231
- await generate();
232
- if (onGenerate && assets.length > 0) {
233
- onGenerate(assets, getManifestJson());
201
+ function NiceFaviconGenerator({
202
+ icon,
203
+ fill = "#1e1e1e",
204
+ manifestConfig,
205
+ onGenerate,
206
+ className = ""
207
+ }) {
208
+ const { t } = useNiceTranslation();
209
+ const {
210
+ config,
211
+ setConfig,
212
+ assets,
213
+ isGenerating,
214
+ generate,
215
+ downloadAll,
216
+ downloadSingle,
217
+ getManifestJson,
218
+ getHtmlTags
219
+ } = useFaviconGenerator(icon, fill, manifestConfig);
220
+ const [activeTab, setActiveTab] = useState("preview");
221
+ const handleGenerate = async () => {
222
+ await generate();
223
+ if (onGenerate && assets.length > 0) {
224
+ onGenerate(assets, getManifestJson());
225
+ }
226
+ };
227
+ return /* @__PURE__ */ jsxs("div", { className: `nice-favicon-generator ${className}`, style: styles.container, children: [
228
+ /* @__PURE__ */ jsxs("div", { style: styles.section, children: [
229
+ /* @__PURE__ */ jsx("h3", { style: styles.sectionTitle, children: t("faviconGenerator.manifestConfiguration", "Manifest Configuration") }),
230
+ /* @__PURE__ */ jsxs("div", { style: styles.formGrid, children: [
231
+ /* @__PURE__ */ jsxs("div", { style: styles.formGroup, children: [
232
+ /* @__PURE__ */ jsx("label", { style: styles.label, children: t("faviconGenerator.appName", "App Name") }),
233
+ /* @__PURE__ */ jsx(
234
+ "input",
235
+ {
236
+ type: "text",
237
+ value: config.name,
238
+ onChange: (e) => setConfig((c) => ({ ...c, name: e.target.value })),
239
+ style: styles.input
240
+ }
241
+ )
242
+ ] }),
243
+ /* @__PURE__ */ jsxs("div", { style: styles.formGroup, children: [
244
+ /* @__PURE__ */ jsx("label", { style: styles.label, children: t("faviconGenerator.shortName", "Short Name") }),
245
+ /* @__PURE__ */ jsx(
246
+ "input",
247
+ {
248
+ type: "text",
249
+ value: config.shortName,
250
+ onChange: (e) => setConfig((c) => ({ ...c, shortName: e.target.value })),
251
+ style: styles.input
252
+ }
253
+ )
254
+ ] }),
255
+ /* @__PURE__ */ jsxs("div", { style: styles.formGroup, children: [
256
+ /* @__PURE__ */ jsx("label", { style: styles.label, children: t("faviconGenerator.themeColor", "Theme Color") }),
257
+ /* @__PURE__ */ jsx(
258
+ "input",
259
+ {
260
+ type: "color",
261
+ value: config.themeColor,
262
+ onChange: (e) => setConfig((c) => ({ ...c, themeColor: e.target.value })),
263
+ style: styles.colorInput
264
+ }
265
+ )
266
+ ] }),
267
+ /* @__PURE__ */ jsxs("div", { style: styles.formGroup, children: [
268
+ /* @__PURE__ */ jsx("label", { style: styles.label, children: t("faviconGenerator.backgroundColor", "Background Color") }),
269
+ /* @__PURE__ */ jsx(
270
+ "input",
271
+ {
272
+ type: "color",
273
+ value: config.backgroundColor,
274
+ onChange: (e) => setConfig((c) => ({ ...c, backgroundColor: e.target.value })),
275
+ style: styles.colorInput
276
+ }
277
+ )
278
+ ] }),
279
+ /* @__PURE__ */ jsxs("div", { style: styles.formGroup, children: [
280
+ /* @__PURE__ */ jsx("label", { style: styles.label, children: t("faviconGenerator.displayMode", "Display Mode") }),
281
+ /* @__PURE__ */ jsxs(
282
+ "select",
283
+ {
284
+ value: config.display,
285
+ onChange: (e) => setConfig((c) => ({ ...c, display: e.target.value })),
286
+ style: styles.input,
287
+ children: [
288
+ /* @__PURE__ */ jsx("option", { value: "standalone", children: t("faviconGenerator.standalone", "Standalone") }),
289
+ /* @__PURE__ */ jsx("option", { value: "fullscreen", children: t("faviconGenerator.fullscreen", "Fullscreen") }),
290
+ /* @__PURE__ */ jsx("option", { value: "minimal-ui", children: t("faviconGenerator.minimalUi", "Minimal UI") }),
291
+ /* @__PURE__ */ jsx("option", { value: "browser", children: t("faviconGenerator.browser", "Browser") })
292
+ ]
293
+ }
294
+ )
295
+ ] }),
296
+ /* @__PURE__ */ jsxs("div", { style: styles.formGroup, children: [
297
+ /* @__PURE__ */ jsx("label", { style: styles.label, children: t("faviconGenerator.startUrl", "Start URL") }),
298
+ /* @__PURE__ */ jsx(
299
+ "input",
300
+ {
301
+ type: "text",
302
+ value: config.startUrl,
303
+ onChange: (e) => setConfig((c) => ({ ...c, startUrl: e.target.value })),
304
+ style: styles.input
305
+ }
306
+ )
307
+ ] })
308
+ ] })
309
+ ] }),
310
+ /* @__PURE__ */ jsxs("div", { style: styles.actions, children: [
311
+ /* @__PURE__ */ jsx(
312
+ "button",
313
+ {
314
+ onClick: handleGenerate,
315
+ disabled: isGenerating,
316
+ style: {
317
+ ...styles.button,
318
+ ...isGenerating ? styles.buttonDisabled : styles.buttonPrimary
319
+ },
320
+ children: isGenerating ? t("faviconGenerator.generating", "Generating...") : t("faviconGenerator.generateFavicons", "Generate Favicons")
234
321
  }
235
- };
236
- return (jsxs("div", { className: `nice-favicon-generator ${className}`, style: styles.container, children: [jsxs("div", { style: styles.section, children: [jsx("h3", { style: styles.sectionTitle, children: t('faviconGenerator.manifestConfiguration', 'Manifest Configuration') }), jsxs("div", { style: styles.formGrid, children: [jsxs("div", { style: styles.formGroup, children: [jsx("label", { style: styles.label, children: t('faviconGenerator.appName', 'App Name') }), jsx("input", { type: "text", value: config.name, onChange: (e) => setConfig((c) => ({ ...c, name: e.target.value })), style: styles.input })] }), jsxs("div", { style: styles.formGroup, children: [jsx("label", { style: styles.label, children: t('faviconGenerator.shortName', 'Short Name') }), jsx("input", { type: "text", value: config.shortName, onChange: (e) => setConfig((c) => ({ ...c, shortName: e.target.value })), style: styles.input })] }), jsxs("div", { style: styles.formGroup, children: [jsx("label", { style: styles.label, children: t('faviconGenerator.themeColor', 'Theme Color') }), jsx("input", { type: "color", value: config.themeColor, onChange: (e) => setConfig((c) => ({ ...c, themeColor: e.target.value })), style: styles.colorInput })] }), jsxs("div", { style: styles.formGroup, children: [jsx("label", { style: styles.label, children: t('faviconGenerator.backgroundColor', 'Background Color') }), jsx("input", { type: "color", value: config.backgroundColor, onChange: (e) => setConfig((c) => ({ ...c, backgroundColor: e.target.value })), style: styles.colorInput })] }), jsxs("div", { style: styles.formGroup, children: [jsx("label", { style: styles.label, children: t('faviconGenerator.displayMode', 'Display Mode') }), jsxs("select", { value: config.display, onChange: (e) => setConfig((c) => ({ ...c, display: e.target.value })), style: styles.input, children: [jsx("option", { value: "standalone", children: t('faviconGenerator.standalone', 'Standalone') }), jsx("option", { value: "fullscreen", children: t('faviconGenerator.fullscreen', 'Fullscreen') }), jsx("option", { value: "minimal-ui", children: t('faviconGenerator.minimalUi', 'Minimal UI') }), jsx("option", { value: "browser", children: t('faviconGenerator.browser', 'Browser') })] })] }), jsxs("div", { style: styles.formGroup, children: [jsx("label", { style: styles.label, children: t('faviconGenerator.startUrl', 'Start URL') }), jsx("input", { type: "text", value: config.startUrl, onChange: (e) => setConfig((c) => ({ ...c, startUrl: e.target.value })), style: styles.input })] })] })] }), jsxs("div", { style: styles.actions, children: [jsx("button", { onClick: handleGenerate, disabled: isGenerating, style: {
237
- ...styles.button,
238
- ...(isGenerating ? styles.buttonDisabled : styles.buttonPrimary),
239
- }, children: isGenerating
240
- ? t('faviconGenerator.generating', 'Generating...')
241
- : t('faviconGenerator.generateFavicons', 'Generate Favicons') }), assets.length > 0 && (jsx("button", { onClick: downloadAll, style: { ...styles.button, ...styles.buttonSecondary }, children: t('faviconGenerator.downloadAll', 'Download All') }))] }), assets.length > 0 && (jsxs("div", { style: styles.section, children: [jsxs("div", { style: styles.tabs, children: [jsx("button", { style: { ...styles.tab, ...(activeTab === 'preview' ? styles.tabActive : {}) }, onClick: () => setActiveTab('preview'), children: t('faviconGenerator.preview', 'Preview') }), jsx("button", { style: { ...styles.tab, ...(activeTab === 'manifest' ? styles.tabActive : {}) }, onClick: () => setActiveTab('manifest'), children: "manifest.json" }), jsx("button", { style: { ...styles.tab, ...(activeTab === 'html' ? styles.tabActive : {}) }, onClick: () => setActiveTab('html'), children: t('faviconGenerator.htmlTags', 'HTML Tags') })] }), activeTab === 'preview' && (jsx("div", { style: styles.assetGrid, children: assets.map((asset) => (jsxs("div", { style: styles.assetCard, children: [jsx("div", { style: styles.assetPreview, children: jsx("img", { src: asset.dataUrl, alt: asset.filename, style: { maxWidth: '64px', maxHeight: '64px' } }) }), jsxs("div", { style: styles.assetInfo, children: [jsx("span", { style: styles.assetName, children: asset.filename }), jsxs("span", { style: styles.assetSize, children: [asset.size, "x", asset.size] }), jsx("span", { style: styles.assetPurpose, children: asset.purpose })] }), jsx("button", { onClick: () => downloadSingle(asset), style: styles.downloadBtn, "aria-label": t('faviconGenerator.download', 'Download {filename}').replace('{filename}', String(asset.filename)), children: jsx(NtdDownload, { size: 14, variant: "outline" }) })] }, asset.filename))) })), activeTab === 'manifest' && jsx("pre", { style: styles.codeBlock, children: getManifestJson() }), activeTab === 'html' && jsx("pre", { style: styles.codeBlock, children: getHtmlTags() })] })), jsxs("div", { style: styles.reference, children: [jsx("h4", { style: styles.referenceTitle, children: t('faviconGenerator.faviconSizesReference', 'Favicon Sizes Reference') }), jsxs("table", { style: styles.table, children: [jsx("thead", { children: jsxs("tr", { children: [jsx("th", { style: styles.th, children: t('faviconGenerator.file', 'File') }), jsx("th", { style: styles.th, children: t('faviconGenerator.size', 'Size') }), jsx("th", { style: styles.th, children: t('faviconGenerator.purpose', 'Purpose') })] }) }), jsx("tbody", { children: FAVICON_SIZES.map((f) => (jsxs("tr", { children: [jsxs("td", { style: styles.td, children: [f.name, ".", f.format] }), jsxs("td", { style: styles.td, children: [f.size, "x", f.size] }), jsx("td", { style: styles.td, children: f.purpose })] }, f.name))) })] })] })] }));
322
+ ),
323
+ assets.length > 0 && /* @__PURE__ */ jsx("button", { onClick: downloadAll, style: { ...styles.button, ...styles.buttonSecondary }, children: t("faviconGenerator.downloadAll", "Download All") })
324
+ ] }),
325
+ assets.length > 0 && /* @__PURE__ */ jsxs("div", { style: styles.section, children: [
326
+ /* @__PURE__ */ jsxs("div", { style: styles.tabs, children: [
327
+ /* @__PURE__ */ jsx(
328
+ "button",
329
+ {
330
+ style: { ...styles.tab, ...activeTab === "preview" ? styles.tabActive : {} },
331
+ onClick: () => setActiveTab("preview"),
332
+ children: t("faviconGenerator.preview", "Preview")
333
+ }
334
+ ),
335
+ /* @__PURE__ */ jsx(
336
+ "button",
337
+ {
338
+ style: { ...styles.tab, ...activeTab === "manifest" ? styles.tabActive : {} },
339
+ onClick: () => setActiveTab("manifest"),
340
+ children: "manifest.json"
341
+ }
342
+ ),
343
+ /* @__PURE__ */ jsx(
344
+ "button",
345
+ {
346
+ style: { ...styles.tab, ...activeTab === "html" ? styles.tabActive : {} },
347
+ onClick: () => setActiveTab("html"),
348
+ children: t("faviconGenerator.htmlTags", "HTML Tags")
349
+ }
350
+ )
351
+ ] }),
352
+ activeTab === "preview" && /* @__PURE__ */ jsx("div", { style: styles.assetGrid, children: assets.map((asset) => /* @__PURE__ */ jsxs("div", { style: styles.assetCard, children: [
353
+ /* @__PURE__ */ jsx("div", { style: styles.assetPreview, children: /* @__PURE__ */ jsx(
354
+ "img",
355
+ {
356
+ src: asset.dataUrl,
357
+ alt: asset.filename,
358
+ style: { maxWidth: "64px", maxHeight: "64px" }
359
+ }
360
+ ) }),
361
+ /* @__PURE__ */ jsxs("div", { style: styles.assetInfo, children: [
362
+ /* @__PURE__ */ jsx("span", { style: styles.assetName, children: asset.filename }),
363
+ /* @__PURE__ */ jsxs("span", { style: styles.assetSize, children: [
364
+ asset.size,
365
+ "x",
366
+ asset.size
367
+ ] }),
368
+ /* @__PURE__ */ jsx("span", { style: styles.assetPurpose, children: asset.purpose })
369
+ ] }),
370
+ /* @__PURE__ */ jsx(
371
+ "button",
372
+ {
373
+ onClick: () => downloadSingle(asset),
374
+ style: styles.downloadBtn,
375
+ "aria-label": t("faviconGenerator.download", "Download {filename}").replace(
376
+ "{filename}",
377
+ String(asset.filename)
378
+ ),
379
+ children: /* @__PURE__ */ jsx(NtdDownload, { size: 14, variant: "outline" })
380
+ }
381
+ )
382
+ ] }, asset.filename)) }),
383
+ activeTab === "manifest" && /* @__PURE__ */ jsx("pre", { style: styles.codeBlock, children: getManifestJson() }),
384
+ activeTab === "html" && /* @__PURE__ */ jsx("pre", { style: styles.codeBlock, children: getHtmlTags() })
385
+ ] }),
386
+ /* @__PURE__ */ jsxs("div", { style: styles.reference, children: [
387
+ /* @__PURE__ */ jsx("h4", { style: styles.referenceTitle, children: t("faviconGenerator.faviconSizesReference", "Favicon Sizes Reference") }),
388
+ /* @__PURE__ */ jsxs("table", { style: styles.table, children: [
389
+ /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { children: [
390
+ /* @__PURE__ */ jsx("th", { style: styles.th, children: t("faviconGenerator.file", "File") }),
391
+ /* @__PURE__ */ jsx("th", { style: styles.th, children: t("faviconGenerator.size", "Size") }),
392
+ /* @__PURE__ */ jsx("th", { style: styles.th, children: t("faviconGenerator.purpose", "Purpose") })
393
+ ] }) }),
394
+ /* @__PURE__ */ jsx("tbody", { children: FAVICON_SIZES.map((f) => /* @__PURE__ */ jsxs("tr", { children: [
395
+ /* @__PURE__ */ jsxs("td", { style: styles.td, children: [
396
+ f.name,
397
+ ".",
398
+ f.format
399
+ ] }),
400
+ /* @__PURE__ */ jsxs("td", { style: styles.td, children: [
401
+ f.size,
402
+ "x",
403
+ f.size
404
+ ] }),
405
+ /* @__PURE__ */ jsx("td", { style: styles.td, children: f.purpose })
406
+ ] }, f.name)) })
407
+ ] })
408
+ ] })
409
+ ] });
242
410
  }
243
- /* ══════════════════════════════════════════════════════════════════════════════
244
- Styles
245
- ══════════════════════════════════════════════════════════════════════════════ */
246
411
  const styles = {
247
- container: {
248
- fontFamily: 'system-ui, -apple-system, sans-serif',
249
- fontSize: '14px',
250
- border: '1px solid #e5e7eb',
251
- borderRadius: '8px',
252
- overflow: 'hidden',
253
- padding: '16px',
254
- },
255
- section: {
256
- marginBottom: '20px',
257
- },
258
- sectionTitle: {
259
- margin: '0 0 12px 0',
260
- fontSize: '15px',
261
- fontWeight: 600,
262
- },
263
- formGrid: {
264
- display: 'grid',
265
- gridTemplateColumns: 'repeat(auto-fill, minmax(200px, 1fr))',
266
- gap: '12px',
267
- },
268
- formGroup: {
269
- display: 'flex',
270
- flexDirection: 'column',
271
- gap: '4px',
272
- },
273
- label: {
274
- fontSize: '12px',
275
- fontWeight: 500,
276
- color: '#6b7280',
277
- },
278
- input: {
279
- padding: '8px 12px',
280
- border: '1px solid #d1d5db',
281
- borderRadius: '6px',
282
- fontSize: '14px',
283
- },
284
- colorInput: {
285
- width: '100%',
286
- height: '36px',
287
- padding: '2px',
288
- border: '1px solid #d1d5db',
289
- borderRadius: '6px',
290
- cursor: 'pointer',
291
- },
292
- actions: {
293
- display: 'flex',
294
- gap: '12px',
295
- marginBottom: '20px',
296
- },
297
- button: {
298
- padding: '10px 20px',
299
- border: 'none',
300
- borderRadius: '6px',
301
- fontSize: '14px',
302
- fontWeight: 500,
303
- cursor: 'pointer',
304
- transition: 'all 0.2s',
305
- },
306
- buttonPrimary: {
307
- backgroundColor: '#3b82f6',
308
- color: 'white',
309
- },
310
- buttonSecondary: {
311
- backgroundColor: '#f3f4f6',
312
- color: '#374151',
313
- border: '1px solid #d1d5db',
314
- },
315
- buttonDisabled: {
316
- backgroundColor: '#e5e7eb',
317
- color: '#9ca3af',
318
- cursor: 'not-allowed',
319
- },
320
- tabs: {
321
- display: 'flex',
322
- borderBottom: '1px solid #e5e7eb',
323
- marginBottom: '16px',
324
- },
325
- tab: {
326
- padding: '8px 16px',
327
- border: 'none',
328
- background: 'none',
329
- cursor: 'pointer',
330
- fontSize: '13px',
331
- color: '#6b7280',
332
- },
333
- tabActive: {
334
- color: '#3b82f6',
335
- borderBottom: '2px solid #3b82f6',
336
- marginBottom: '-1px',
337
- },
338
- assetGrid: {
339
- display: 'grid',
340
- gridTemplateColumns: 'repeat(auto-fill, minmax(250px, 1fr))',
341
- gap: '12px',
342
- },
343
- assetCard: {
344
- display: 'flex',
345
- alignItems: 'center',
346
- gap: '12px',
347
- padding: '12px',
348
- border: '1px solid #e5e7eb',
349
- borderRadius: '8px',
350
- backgroundColor: '#fafafa',
351
- },
352
- assetPreview: {
353
- width: '64px',
354
- height: '64px',
355
- display: 'flex',
356
- alignItems: 'center',
357
- justifyContent: 'center',
358
- backgroundColor: 'white',
359
- borderRadius: '4px',
360
- border: '1px solid #e5e7eb',
361
- },
362
- assetInfo: {
363
- flex: 1,
364
- display: 'flex',
365
- flexDirection: 'column',
366
- gap: '2px',
367
- },
368
- assetName: {
369
- fontSize: '13px',
370
- fontWeight: 500,
371
- },
372
- assetSize: {
373
- fontSize: '11px',
374
- color: '#6b7280',
375
- },
376
- assetPurpose: {
377
- fontSize: '11px',
378
- color: '#9ca3af',
379
- },
380
- downloadBtn: {
381
- width: '32px',
382
- height: '32px',
383
- border: '1px solid #d1d5db',
384
- borderRadius: '6px',
385
- backgroundColor: 'white',
386
- cursor: 'pointer',
387
- fontSize: '16px',
388
- },
389
- codeBlock: {
390
- padding: '16px',
391
- backgroundColor: '#1e1e1e',
392
- color: '#d4d4d4',
393
- borderRadius: '8px',
394
- fontSize: '12px',
395
- fontFamily: 'monospace',
396
- overflow: 'auto',
397
- whiteSpace: 'pre-wrap',
398
- },
399
- reference: {
400
- marginTop: '20px',
401
- padding: '16px',
402
- backgroundColor: '#f9fafb',
403
- borderRadius: '8px',
404
- },
405
- referenceTitle: {
406
- margin: '0 0 12px 0',
407
- fontSize: '13px',
408
- fontWeight: 600,
409
- color: '#6b7280',
410
- },
411
- table: {
412
- width: '100%',
413
- borderCollapse: 'collapse',
414
- fontSize: '12px',
415
- },
416
- th: {
417
- textAlign: 'left',
418
- padding: '8px',
419
- borderBottom: '1px solid #e5e7eb',
420
- fontWeight: 600,
421
- color: '#374151',
422
- },
423
- td: {
424
- padding: '8px',
425
- borderBottom: '1px solid #f3f4f6',
426
- color: '#6b7280',
427
- },
412
+ container: {
413
+ fontFamily: "system-ui, -apple-system, sans-serif",
414
+ fontSize: "14px",
415
+ border: "1px solid #e5e7eb",
416
+ borderRadius: "8px",
417
+ overflow: "hidden",
418
+ padding: "16px"
419
+ },
420
+ section: {
421
+ marginBottom: "20px"
422
+ },
423
+ sectionTitle: {
424
+ margin: "0 0 12px 0",
425
+ fontSize: "15px",
426
+ fontWeight: 600
427
+ },
428
+ formGrid: {
429
+ display: "grid",
430
+ gridTemplateColumns: "repeat(auto-fill, minmax(200px, 1fr))",
431
+ gap: "12px"
432
+ },
433
+ formGroup: {
434
+ display: "flex",
435
+ flexDirection: "column",
436
+ gap: "4px"
437
+ },
438
+ label: {
439
+ fontSize: "12px",
440
+ fontWeight: 500,
441
+ color: "#6b7280"
442
+ },
443
+ input: {
444
+ padding: "8px 12px",
445
+ border: "1px solid #d1d5db",
446
+ borderRadius: "6px",
447
+ fontSize: "14px"
448
+ },
449
+ colorInput: {
450
+ width: "100%",
451
+ height: "36px",
452
+ padding: "2px",
453
+ border: "1px solid #d1d5db",
454
+ borderRadius: "6px",
455
+ cursor: "pointer"
456
+ },
457
+ actions: {
458
+ display: "flex",
459
+ gap: "12px",
460
+ marginBottom: "20px"
461
+ },
462
+ button: {
463
+ padding: "10px 20px",
464
+ border: "none",
465
+ borderRadius: "6px",
466
+ fontSize: "14px",
467
+ fontWeight: 500,
468
+ cursor: "pointer",
469
+ transition: "all 0.2s"
470
+ },
471
+ buttonPrimary: {
472
+ backgroundColor: "#3b82f6",
473
+ color: "white"
474
+ },
475
+ buttonSecondary: {
476
+ backgroundColor: "#f3f4f6",
477
+ color: "#374151",
478
+ border: "1px solid #d1d5db"
479
+ },
480
+ buttonDisabled: {
481
+ backgroundColor: "#e5e7eb",
482
+ color: "#9ca3af",
483
+ cursor: "not-allowed"
484
+ },
485
+ tabs: {
486
+ display: "flex",
487
+ borderBottom: "1px solid #e5e7eb",
488
+ marginBottom: "16px"
489
+ },
490
+ tab: {
491
+ padding: "8px 16px",
492
+ border: "none",
493
+ background: "none",
494
+ cursor: "pointer",
495
+ fontSize: "13px",
496
+ color: "#6b7280"
497
+ },
498
+ tabActive: {
499
+ color: "#3b82f6",
500
+ borderBottom: "2px solid #3b82f6",
501
+ marginBottom: "-1px"
502
+ },
503
+ assetGrid: {
504
+ display: "grid",
505
+ gridTemplateColumns: "repeat(auto-fill, minmax(250px, 1fr))",
506
+ gap: "12px"
507
+ },
508
+ assetCard: {
509
+ display: "flex",
510
+ alignItems: "center",
511
+ gap: "12px",
512
+ padding: "12px",
513
+ border: "1px solid #e5e7eb",
514
+ borderRadius: "8px",
515
+ backgroundColor: "#fafafa"
516
+ },
517
+ assetPreview: {
518
+ width: "64px",
519
+ height: "64px",
520
+ display: "flex",
521
+ alignItems: "center",
522
+ justifyContent: "center",
523
+ backgroundColor: "white",
524
+ borderRadius: "4px",
525
+ border: "1px solid #e5e7eb"
526
+ },
527
+ assetInfo: {
528
+ flex: 1,
529
+ display: "flex",
530
+ flexDirection: "column",
531
+ gap: "2px"
532
+ },
533
+ assetName: {
534
+ fontSize: "13px",
535
+ fontWeight: 500
536
+ },
537
+ assetSize: {
538
+ fontSize: "11px",
539
+ color: "#6b7280"
540
+ },
541
+ assetPurpose: {
542
+ fontSize: "11px",
543
+ color: "#9ca3af"
544
+ },
545
+ downloadBtn: {
546
+ width: "32px",
547
+ height: "32px",
548
+ border: "1px solid #d1d5db",
549
+ borderRadius: "6px",
550
+ backgroundColor: "white",
551
+ cursor: "pointer",
552
+ fontSize: "16px"
553
+ },
554
+ codeBlock: {
555
+ padding: "16px",
556
+ backgroundColor: "#1e1e1e",
557
+ color: "#d4d4d4",
558
+ borderRadius: "8px",
559
+ fontSize: "12px",
560
+ fontFamily: "monospace",
561
+ overflow: "auto",
562
+ whiteSpace: "pre-wrap"
563
+ },
564
+ reference: {
565
+ marginTop: "20px",
566
+ padding: "16px",
567
+ backgroundColor: "#f9fafb",
568
+ borderRadius: "8px"
569
+ },
570
+ referenceTitle: {
571
+ margin: "0 0 12px 0",
572
+ fontSize: "13px",
573
+ fontWeight: 600,
574
+ color: "#6b7280"
575
+ },
576
+ table: {
577
+ width: "100%",
578
+ borderCollapse: "collapse",
579
+ fontSize: "12px"
580
+ },
581
+ th: {
582
+ textAlign: "left",
583
+ padding: "8px",
584
+ borderBottom: "1px solid #e5e7eb",
585
+ fontWeight: 600,
586
+ color: "#374151"
587
+ },
588
+ td: {
589
+ padding: "8px",
590
+ borderBottom: "1px solid #f3f4f6",
591
+ color: "#6b7280"
592
+ }
593
+ };
594
+ export {
595
+ NiceFaviconGenerator,
596
+ useFaviconGenerator
428
597
  };
429
-
430
- export { NiceFaviconGenerator, useFaviconGenerator };