neoagent 2.4.1-beta.23 → 2.4.1-beta.24

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 (84) hide show
  1. package/extensions/chrome-browser/icons/icon128.png +0 -0
  2. package/extensions/chrome-browser/icons/icon16.png +0 -0
  3. package/extensions/chrome-browser/icons/icon48.png +0 -0
  4. package/extensions/chrome-browser/icons/logo.svg +39 -18
  5. package/flutter_app/android/app/src/main/res/mipmap-hdpi/ic_launcher.png +0 -0
  6. package/flutter_app/android/app/src/main/res/mipmap-mdpi/ic_launcher.png +0 -0
  7. package/flutter_app/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png +0 -0
  8. package/flutter_app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png +0 -0
  9. package/flutter_app/assets/branding/app_icon_1024.png +0 -0
  10. package/flutter_app/assets/branding/app_icon_128.png +0 -0
  11. package/flutter_app/assets/branding/app_icon_192.png +0 -0
  12. package/flutter_app/assets/branding/app_icon_256.png +0 -0
  13. package/flutter_app/assets/branding/app_icon_32.png +0 -0
  14. package/flutter_app/assets/branding/app_icon_512.png +0 -0
  15. package/flutter_app/assets/branding/app_icon_64.png +0 -0
  16. package/flutter_app/assets/branding/app_icon_light_1024.png +0 -0
  17. package/flutter_app/assets/branding/app_icon_light_128.png +0 -0
  18. package/flutter_app/assets/branding/app_icon_light_192.png +0 -0
  19. package/flutter_app/assets/branding/app_icon_light_256.png +0 -0
  20. package/flutter_app/assets/branding/app_icon_light_32.png +0 -0
  21. package/flutter_app/assets/branding/app_icon_light_512.png +0 -0
  22. package/flutter_app/assets/branding/app_icon_light_64.png +0 -0
  23. package/flutter_app/assets/branding/tray_icon_light_template.png +0 -0
  24. package/flutter_app/assets/branding/tray_icon_template.png +0 -0
  25. package/flutter_app/lib/features/onboarding/onboarding_chrome.dart +1 -1
  26. package/flutter_app/lib/features/onboarding/onboarding_companion_step.dart +1 -1
  27. package/flutter_app/lib/features/onboarding/onboarding_model_step.dart +1 -1
  28. package/flutter_app/lib/features/onboarding/onboarding_welcome_step.dart +2 -2
  29. package/flutter_app/lib/main_app_shell.dart +7 -7
  30. package/flutter_app/lib/main_shared.dart +1 -1
  31. package/flutter_app/linux/runner/resources/app_icon.png +0 -0
  32. package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png +0 -0
  33. package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png +0 -0
  34. package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png +0 -0
  35. package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png +0 -0
  36. package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png +0 -0
  37. package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png +0 -0
  38. package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png +0 -0
  39. package/flutter_app/tool/branding_source/neoagent-icon-1024.png +0 -0
  40. package/flutter_app/tool/branding_source/neoagent-icon-128.png +0 -0
  41. package/flutter_app/tool/branding_source/neoagent-icon-16.png +0 -0
  42. package/flutter_app/tool/branding_source/neoagent-icon-180.png +0 -0
  43. package/flutter_app/tool/branding_source/neoagent-icon-192.png +0 -0
  44. package/flutter_app/tool/branding_source/neoagent-icon-256.png +0 -0
  45. package/flutter_app/tool/branding_source/neoagent-icon-32.png +0 -0
  46. package/flutter_app/tool/branding_source/neoagent-icon-48.png +0 -0
  47. package/flutter_app/tool/branding_source/neoagent-icon-512.png +0 -0
  48. package/flutter_app/tool/branding_source/neoagent-icon-64.png +0 -0
  49. package/flutter_app/tool/branding_source/neoagent-icon.svg +43 -0
  50. package/flutter_app/tool/generate_desktop_branding.py +137 -277
  51. package/flutter_app/web/favicon.png +0 -0
  52. package/flutter_app/web/favicon.svg +39 -18
  53. package/flutter_app/web/favicon_light.svg +39 -18
  54. package/flutter_app/web/icons/Icon-192-light.png +0 -0
  55. package/flutter_app/web/icons/Icon-192.png +0 -0
  56. package/flutter_app/web/icons/Icon-512-light.png +0 -0
  57. package/flutter_app/web/icons/Icon-512.png +0 -0
  58. package/flutter_app/web/icons/Icon-maskable-192-light.png +0 -0
  59. package/flutter_app/web/icons/Icon-maskable-192.png +0 -0
  60. package/flutter_app/web/icons/Icon-maskable-512-light.png +0 -0
  61. package/flutter_app/web/icons/Icon-maskable-512.png +0 -0
  62. package/flutter_app/windows/runner/resources/app_icon.ico +0 -0
  63. package/package.json +1 -1
  64. package/server/public/.last_build_id +1 -1
  65. package/server/public/assets/assets/branding/app_icon_256.png +0 -0
  66. package/server/public/assets/assets/branding/app_icon_512.png +0 -0
  67. package/server/public/assets/assets/branding/app_icon_light_256.png +0 -0
  68. package/server/public/assets/assets/branding/app_icon_light_512.png +0 -0
  69. package/server/public/assets/assets/branding/tray_icon_light_template.png +0 -0
  70. package/server/public/assets/assets/branding/tray_icon_template.png +0 -0
  71. package/server/public/assets/web/icons/Icon-192.png +0 -0
  72. package/server/public/favicon.png +0 -0
  73. package/server/public/favicon.svg +39 -18
  74. package/server/public/favicon_light.svg +39 -18
  75. package/server/public/flutter_bootstrap.js +2 -2
  76. package/server/public/icons/Icon-192-light.png +0 -0
  77. package/server/public/icons/Icon-192.png +0 -0
  78. package/server/public/icons/Icon-512-light.png +0 -0
  79. package/server/public/icons/Icon-512.png +0 -0
  80. package/server/public/icons/Icon-maskable-192-light.png +0 -0
  81. package/server/public/icons/Icon-maskable-192.png +0 -0
  82. package/server/public/icons/Icon-maskable-512-light.png +0 -0
  83. package/server/public/icons/Icon-maskable-512.png +0 -0
  84. package/server/public/main.dart.js +111 -111
@@ -4,10 +4,11 @@ from __future__ import annotations
4
4
 
5
5
  from pathlib import Path
6
6
 
7
- from PIL import Image, ImageDraw, ImageFilter
7
+ from PIL import Image, ImageDraw
8
8
 
9
9
 
10
10
  ROOT = Path(__file__).resolve().parents[1]
11
+ SOURCE_DIR = ROOT / "tool" / "branding_source"
11
12
  BRANDING_DIR = ROOT / "assets" / "branding"
12
13
  WEB_DIR = ROOT / "web"
13
14
  WEB_ICONS_DIR = WEB_DIR / "icons"
@@ -19,294 +20,146 @@ SERVER_PUBLIC_DIR = ROOT.parent / "server" / "public"
19
20
  SERVER_PUBLIC_ICONS_DIR = SERVER_PUBLIC_DIR / "icons"
20
21
  STATIC_IMG_DIR = ROOT.parent / "static" / "img"
21
22
  LANDING_LOGO_PATH = ROOT.parent / "landing" / "assets" / "logo.svg"
22
- EXTENSION_LOGO_PATH = ROOT.parent / "extensions" / "chrome-browser" / "icons" / "logo.svg"
23
+ EXTENSION_ICON_DIR = ROOT.parent / "extensions" / "chrome-browser" / "icons"
24
+ EXTENSION_LOGO_PATH = EXTENSION_ICON_DIR / "logo.svg"
23
25
 
24
- ACCENT = (104, 78, 44)
25
- ACCENT_ALT = (35, 92, 82)
26
- ACCENT_DARK = (158, 128, 82)
27
- ACCENT_ALT_DARK = (67, 144, 129)
28
- SYMBOL_LIGHT = (255, 247, 232, 255)
29
- WHITE = (255, 255, 255, 255)
26
+ SOURCE_SVG = SOURCE_DIR / "neoagent-icon.svg"
27
+ SOURCE_PNG_SIZES = (16, 32, 48, 64, 128, 180, 192, 256, 512, 1024)
30
28
  TRANSPARENT = (0, 0, 0, 0)
29
+ WHITE = (255, 255, 255, 255)
30
+ BLACK = (0, 0, 0, 255)
31
31
 
32
32
 
33
- def lerp(a: float, b: float, t: float) -> float:
34
- return a + (b - a) * t
35
-
36
-
37
- def mix_channel(value: int, target: int, amount: float) -> int:
38
- return max(0, min(255, round(lerp(value, target, amount))))
39
-
40
-
41
- def mix_color(color: tuple[int, int, int], target: int, amount: float) -> tuple[int, int, int]:
42
- return (
43
- mix_channel(color[0], target, amount),
44
- mix_channel(color[1], target, amount),
45
- mix_channel(color[2], target, amount),
46
- )
33
+ def ensure_dirs() -> None:
34
+ BRANDING_DIR.mkdir(parents=True, exist_ok=True)
35
+ WEB_ICONS_DIR.mkdir(parents=True, exist_ok=True)
36
+ MAC_ICON_DIR.mkdir(parents=True, exist_ok=True)
37
+ LINUX_ICON_DIR.mkdir(parents=True, exist_ok=True)
38
+ SERVER_PUBLIC_ICONS_DIR.mkdir(parents=True, exist_ok=True)
39
+ STATIC_IMG_DIR.mkdir(parents=True, exist_ok=True)
40
+ LANDING_LOGO_PATH.parent.mkdir(parents=True, exist_ok=True)
41
+ EXTENSION_ICON_DIR.mkdir(parents=True, exist_ok=True)
47
42
 
48
43
 
49
- def gradient_background(
50
- size: int,
51
- start: tuple[int, int, int],
52
- end: tuple[int, int, int],
53
- ) -> Image.Image:
54
- img = Image.new("RGBA", (size, size), TRANSPARENT)
55
- px = img.load()
56
- for y in range(size):
57
- for x in range(size):
58
- tx = x / max(size - 1, 1)
59
- ty = y / max(size - 1, 1)
60
- diagonal = (tx * 0.58) + (ty * 0.42)
61
- glow = max(0.0, 1.0 - (((tx - 0.25) ** 2 + (ty - 0.18) ** 2) ** 0.5) / 0.58)
62
- shade = max(0.0, 1.0 - (((tx - 0.86) ** 2 + (ty - 0.94) ** 2) ** 0.5) / 0.72)
63
- t = min(1.0, max(0.0, diagonal + glow * 0.12 - shade * 0.08))
64
- base = (
65
- int(lerp(start[0], end[0], t)),
66
- int(lerp(start[1], end[1], t)),
67
- int(lerp(start[2], end[2], t)),
68
- )
69
- lit = mix_color(base, 255, glow * 0.14)
70
- final = mix_color(lit, 0, shade * 0.16)
71
- px[x, y] = (
72
- final[0],
73
- final[1],
74
- final[2],
75
- 255,
76
- )
77
- return img
44
+ def source_png_path(size: int) -> Path:
45
+ return SOURCE_DIR / f"neoagent-icon-{size}.png"
78
46
 
79
47
 
80
- def logo_paths(size: int, padding_ratio: float = 0.16):
81
- pad = size * padding_ratio
82
- inner = size - pad * 2
83
- def point(x: float, y: float) -> tuple[float, float]:
84
- return (pad + inner * x, pad + inner * y)
48
+ def load_source_icon(size: int) -> Image.Image:
49
+ if size in SOURCE_PNG_SIZES and source_png_path(size).exists():
50
+ return Image.open(source_png_path(size)).convert("RGBA")
51
+ source = Image.open(source_png_path(1024)).convert("RGBA")
52
+ return source.resize((size, size), Image.Resampling.LANCZOS)
85
53
 
86
- top = [point(0.5, 0.08), point(0.92, 0.35), point(0.5, 0.53), point(0.08, 0.35)]
87
- middle = [point(0.5, 0.43), point(0.9, 0.64), point(0.5, 0.76), point(0.1, 0.64)]
88
- bottom = [point(0.5, 0.67), point(0.86, 0.86), point(0.5, 0.96), point(0.14, 0.86)]
89
- return top, middle, bottom
90
54
 
55
+ def save_icon(path: Path, size: int) -> None:
56
+ path.parent.mkdir(parents=True, exist_ok=True)
57
+ image = load_source_icon(size)
58
+ if image.size != (size, size):
59
+ image = image.resize((size, size), Image.Resampling.LANCZOS)
60
+ image.save(path, format="PNG")
91
61
 
92
- def draw_logo(draw: ImageDraw.ImageDraw, size: int, color: tuple[int, int, int, int]) -> None:
93
- top, middle, bottom = logo_paths(size)
94
- draw.polygon(top, fill=color)
95
- draw.polygon(middle, fill=color)
96
- draw.polygon(bottom, fill=color)
97
62
 
63
+ def write_source_svg(path: Path) -> None:
64
+ path.parent.mkdir(parents=True, exist_ok=True)
65
+ svg = SOURCE_SVG.read_text(encoding="utf-8")
66
+ svg = svg.replace(
67
+ 'stroke="rgba(255,255,255,0.16)"',
68
+ 'stroke="#ffffff" stroke-opacity="0.16"',
69
+ )
70
+ path.write_text(svg, encoding="utf-8")
98
71
 
99
- def make_app_icon(size: int, *, light: bool = False) -> Image.Image:
100
- canvas = Image.new("RGBA", (size, size), TRANSPARENT)
101
- start = ACCENT if light else ACCENT_DARK
102
- end = ACCENT_ALT if light else ACCENT_ALT_DARK
103
- symbol = SYMBOL_LIGHT if light else WHITE
104
72
 
105
- shadow = Image.new("RGBA", (size, size), TRANSPARENT)
106
- shadow_draw = ImageDraw.Draw(shadow)
107
- corner = round(size * 0.3)
108
- shadow_draw.rounded_rectangle(
109
- (size * 0.075, size * 0.09, size * 0.925, size * 0.94),
110
- radius=corner,
111
- fill=(0, 0, 0, 64 if light else 86),
112
- )
113
- shadow = shadow.filter(ImageFilter.GaussianBlur(radius=max(2, size * 0.035)))
114
- canvas.alpha_composite(shadow)
115
-
116
- base_mask = Image.new("L", (size, size), 0)
117
- mask_draw = ImageDraw.Draw(base_mask)
118
- base_rect = (size * 0.08, size * 0.08, size * 0.92, size * 0.92)
119
- mask_draw.rounded_rectangle(base_rect, radius=corner, fill=255)
120
-
121
- base = gradient_background(size, start, end)
122
- clipped = Image.new("RGBA", (size, size), TRANSPARENT)
123
- clipped.paste(base, mask=base_mask)
124
- canvas.alpha_composite(clipped)
125
-
126
- shine = Image.new("RGBA", (size, size), TRANSPARENT)
127
- shine_draw = ImageDraw.Draw(shine)
128
- shine_draw.ellipse(
129
- (size * -0.12, size * -0.18, size * 0.78, size * 0.58),
130
- fill=(255, 255, 255, 30 if light else 42),
131
- )
132
- shine.putalpha(Image.composite(shine.getchannel("A"), Image.new("L", (size, size), 0), base_mask))
133
- canvas.alpha_composite(shine)
134
-
135
- lower_glaze = Image.new("RGBA", (size, size), TRANSPARENT)
136
- lower_draw = ImageDraw.Draw(lower_glaze)
137
- lower_draw.rounded_rectangle(
138
- base_rect,
139
- radius=corner,
140
- fill=(0, 0, 0, 18 if light else 12),
141
- )
142
- lower_mask = Image.new("L", (size, size), 0)
143
- lower_mask_draw = ImageDraw.Draw(lower_mask)
144
- lower_mask_draw.rectangle((0, size * 0.55, size, size), fill=255)
145
- lower_glaze.putalpha(Image.composite(lower_glaze.getchannel("A"), Image.new("L", (size, size), 0), lower_mask))
146
- canvas.alpha_composite(lower_glaze)
147
-
148
- ring = Image.new("RGBA", (size, size), TRANSPARENT)
149
- ring_draw = ImageDraw.Draw(ring)
150
- ring_draw.rounded_rectangle(
151
- base_rect,
152
- radius=corner,
153
- outline=(255, 255, 255, 58 if light else 48),
154
- width=max(1, round(size * 0.012)),
155
- )
156
- inset = size * 0.018
157
- ring_draw.rounded_rectangle(
73
+ def draw_scaled_circle(
74
+ draw: ImageDraw.ImageDraw,
75
+ size: int,
76
+ center_x: float,
77
+ center_y: float,
78
+ radius: float,
79
+ color: tuple[int, int, int, int],
80
+ ) -> None:
81
+ scale = size / 100
82
+ draw.ellipse(
158
83
  (
159
- base_rect[0] + inset,
160
- base_rect[1] + inset,
161
- base_rect[2] - inset,
162
- base_rect[3] - inset,
84
+ (center_x - radius) * scale,
85
+ (center_y - radius) * scale,
86
+ (center_x + radius) * scale,
87
+ (center_y + radius) * scale,
163
88
  ),
164
- radius=max(1, corner - round(inset)),
165
- outline=(0, 0, 0, 26 if light else 20),
166
- width=max(1, round(size * 0.006)),
167
- )
168
- canvas.alpha_composite(ring)
169
-
170
- glyph_shadow = Image.new("RGBA", (size, size), TRANSPARENT)
171
- shadow_draw = ImageDraw.Draw(glyph_shadow)
172
- draw_logo(shadow_draw, size, (0, 0, 0, 76 if light else 58))
173
- glyph_shadow = glyph_shadow.transform(
174
- glyph_shadow.size,
175
- Image.Transform.AFFINE,
176
- (1, 0, 0, 0, 1, size * 0.018),
177
- resample=Image.Resampling.BICUBIC,
89
+ fill=color,
178
90
  )
179
- glyph_shadow = glyph_shadow.filter(ImageFilter.GaussianBlur(radius=max(1, size * 0.006)))
180
- canvas.alpha_composite(glyph_shadow)
181
-
182
- glyph = Image.new("RGBA", (size, size), TRANSPARENT)
183
- draw = ImageDraw.Draw(glyph)
184
- draw_logo(draw, size, symbol)
185
- canvas.alpha_composite(glyph)
186
-
187
- glyph_highlight = Image.new("RGBA", (size, size), TRANSPARENT)
188
- highlight_draw = ImageDraw.Draw(glyph_highlight)
189
- draw_logo(highlight_draw, size, (255, 255, 255, 26 if light else 34))
190
- glyph_highlight = glyph_highlight.transform(
191
- glyph_highlight.size,
192
- Image.Transform.AFFINE,
193
- (1, 0, 0, 0, 1, -size * 0.012),
194
- resample=Image.Resampling.BICUBIC,
195
- )
196
- canvas.alpha_composite(glyph_highlight)
197
- return canvas
198
91
 
199
92
 
200
93
  def make_tray_template(
201
94
  size: int = 64,
202
- color: tuple[int, int, int, int] = (0, 0, 0, 255),
95
+ color: tuple[int, int, int, int] = BLACK,
203
96
  ) -> Image.Image:
204
97
  img = Image.new("RGBA", (size, size), TRANSPARENT)
205
98
  draw = ImageDraw.Draw(img)
206
- draw_logo(draw, size, color)
207
- return img
208
-
99
+ scale = size / 100
100
+ width = max(2, round(size * 0.078))
101
+ center = 50 * scale
209
102
 
210
- def ensure_dirs() -> None:
211
- BRANDING_DIR.mkdir(parents=True, exist_ok=True)
212
- WEB_ICONS_DIR.mkdir(parents=True, exist_ok=True)
213
- MAC_ICON_DIR.mkdir(parents=True, exist_ok=True)
214
- LINUX_ICON_DIR.mkdir(parents=True, exist_ok=True)
215
- SERVER_PUBLIC_ICONS_DIR.mkdir(parents=True, exist_ok=True)
216
- STATIC_IMG_DIR.mkdir(parents=True, exist_ok=True)
217
- LANDING_LOGO_PATH.parent.mkdir(parents=True, exist_ok=True)
218
- EXTENSION_LOGO_PATH.parent.mkdir(parents=True, exist_ok=True)
103
+ draw.arc(
104
+ (
105
+ (50 - 30) * scale,
106
+ (50 - 30) * scale,
107
+ (50 + 30) * scale,
108
+ (50 + 30) * scale,
109
+ ),
110
+ start=158,
111
+ end=444,
112
+ fill=color,
113
+ width=width,
114
+ )
115
+ draw.arc(
116
+ (
117
+ (50 - 17) * scale,
118
+ (50 - 17) * scale,
119
+ (50 + 17) * scale,
120
+ (50 + 17) * scale,
121
+ ),
122
+ start=68,
123
+ end=330,
124
+ fill=color,
125
+ width=width,
126
+ )
127
+ draw_scaled_circle(draw, size, 50, 50, 7, color)
128
+ draw_scaled_circle(draw, size, 50, 20, 5.6, color)
129
+
130
+ # Slightly round arc ends so the template keeps the supplied logo's soft tube feel.
131
+ end_radius = width / 2
132
+ for x, y in ((77.2, 74.8), (80.0, 41.2), (32.0, 29.7), (68.8, 39.2)):
133
+ draw.ellipse(
134
+ (
135
+ x * scale - end_radius,
136
+ y * scale - end_radius,
137
+ x * scale + end_radius,
138
+ y * scale + end_radius,
139
+ ),
140
+ fill=color,
141
+ )
219
142
 
143
+ # Keep the symbol optically centered inside the menu-bar bounds.
144
+ return img.crop((0, 2, size, size + 2))
220
145
 
221
- def write_text(path: Path, content: str) -> None:
222
- path.write_text(content, encoding="utf-8")
223
146
 
147
+ def main() -> None:
148
+ ensure_dirs()
224
149
 
225
- def copy_png(image: Image.Image, path: Path, size: int) -> None:
226
- path.parent.mkdir(parents=True, exist_ok=True)
227
- save_png(image, path, size)
228
-
229
-
230
- def write_favicon_svg(path: Path, *, light: bool = False) -> None:
231
- start = ACCENT if light else ACCENT_DARK
232
- end = ACCENT_ALT if light else ACCENT_ALT_DARK
233
- symbol = "#fff9ed" if light else "#ffffff"
234
- stroke = "#000000" if light else "#ffffff"
235
- stroke_opacity = "0.24" if light else "0.16"
236
- glow = "#ffffff" if light else "#fff4d8"
237
- top_opacity = "0.20" if light else "0.24"
238
- shade_opacity = "0.12" if light else "0.08"
239
- svg = f"""<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
240
- <defs>
241
- <linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
242
- <stop offset="0%" stop-color="#{start[0]:02x}{start[1]:02x}{start[2]:02x}"/>
243
- <stop offset="100%" stop-color="#{end[0]:02x}{end[1]:02x}{end[2]:02x}"/>
244
- </linearGradient>
245
- <radialGradient id="shine" cx="24%" cy="15%" r="70%">
246
- <stop offset="0%" stop-color="{glow}" stop-opacity="{top_opacity}"/>
247
- <stop offset="100%" stop-color="{glow}" stop-opacity="0"/>
248
- </radialGradient>
249
- </defs>
250
- <rect x="2.5" y="2.5" width="27" height="27" rx="9" ry="9" fill="url(#bg)" stroke="{stroke}" stroke-opacity="{stroke_opacity}" stroke-width="1"/>
251
- <rect x="2.5" y="2.5" width="27" height="27" rx="9" ry="9" fill="url(#shine)"/>
252
- <path d="M2.5 17h27v3.5c0 5-4 9-9 9h-9c-5 0-9-4-9-9Z" fill="#000000" opacity="{shade_opacity}"/>
253
- <rect x="3" y="3" width="26" height="26" rx="8.5" ry="8.5" fill="none" stroke="#ffffff" stroke-opacity="0.18" stroke-width="1"/>
254
- <path d="M16 6.25 26.15 12.3 16 16.3 5.85 12.3Z" fill="#000000" opacity="0.20" transform="translate(0 0.65)"/>
255
- <path d="M16 14.75 25.85 19.45 16 22.25 6.15 19.45Z" fill="#000000" opacity="0.20" transform="translate(0 0.65)"/>
256
- <path d="M16 20.45 24.85 24.75 16 26.85 7.15 24.75Z" fill="#000000" opacity="0.20" transform="translate(0 0.65)"/>
257
- <path d="M16 5.7 26.8 12.1 16 16.5 5.2 12.1Z" fill="{symbol}"/>
258
- <path d="M16 14.2 26.5 19.3 16 22.4 5.5 19.3Z" fill="{symbol}"/>
259
- <path d="M16 20 25.4 24.6 16 27 6.6 24.6Z" fill="{symbol}"/>
260
- </svg>
261
- """
262
- write_text(path, svg)
263
-
264
-
265
- def save_png(image: Image.Image, path: Path, size: int) -> None:
266
- image.resize((size, size), Image.Resampling.LANCZOS).save(path, format="PNG")
150
+ for size in (1024, 512, 256, 192, 128, 64, 32):
151
+ save_icon(BRANDING_DIR / f"app_icon_{size}.png", size)
152
+ save_icon(BRANDING_DIR / f"app_icon_light_{size}.png", size)
267
153
 
154
+ make_tray_template(64).save(BRANDING_DIR / "tray_icon_template.png", format="PNG")
155
+ make_tray_template(64, WHITE).save(BRANDING_DIR / "tray_icon_light_template.png", format="PNG")
268
156
 
269
- def main() -> None:
270
- ensure_dirs()
271
- master = make_app_icon(1024)
272
- light_master = make_app_icon(1024, light=True)
273
-
274
- save_png(master, BRANDING_DIR / "app_icon_1024.png", 1024)
275
- save_png(master, BRANDING_DIR / "app_icon_512.png", 512)
276
- save_png(master, BRANDING_DIR / "app_icon_256.png", 256)
277
- save_png(master, BRANDING_DIR / "app_icon_192.png", 192)
278
- save_png(master, BRANDING_DIR / "app_icon_128.png", 128)
279
- save_png(master, BRANDING_DIR / "app_icon_64.png", 64)
280
- save_png(master, BRANDING_DIR / "app_icon_32.png", 32)
281
- save_png(light_master, BRANDING_DIR / "app_icon_light_1024.png", 1024)
282
- save_png(light_master, BRANDING_DIR / "app_icon_light_512.png", 512)
283
- save_png(light_master, BRANDING_DIR / "app_icon_light_256.png", 256)
284
- save_png(light_master, BRANDING_DIR / "app_icon_light_192.png", 192)
285
- save_png(light_master, BRANDING_DIR / "app_icon_light_128.png", 128)
286
- save_png(light_master, BRANDING_DIR / "app_icon_light_64.png", 64)
287
- save_png(light_master, BRANDING_DIR / "app_icon_light_32.png", 32)
288
-
289
- tray = make_tray_template(64)
290
- save_png(tray, BRANDING_DIR / "tray_icon_template.png", 64)
291
- light_tray = make_tray_template(64, WHITE)
292
- save_png(light_tray, BRANDING_DIR / "tray_icon_light_template.png", 64)
293
-
294
- icon_sizes = {
295
- 16: "app_icon_16.png",
296
- 32: "app_icon_32.png",
297
- 64: "app_icon_64.png",
298
- 128: "app_icon_128.png",
299
- 256: "app_icon_256.png",
300
- 512: "app_icon_512.png",
301
- 1024: "app_icon_1024.png",
302
- }
303
- for size, filename in icon_sizes.items():
304
- save_png(master, MAC_ICON_DIR / filename, size)
157
+ for size in (16, 32, 64, 128, 256, 512, 1024):
158
+ save_icon(MAC_ICON_DIR / f"app_icon_{size}.png", size)
305
159
 
306
- save_png(master, LINUX_ICON_DIR / "app_icon.png", 256)
160
+ save_icon(LINUX_ICON_DIR / "app_icon.png", 256)
307
161
 
308
- master_for_ico = master.resize((256, 256), Image.Resampling.LANCZOS)
309
- master_for_ico.save(
162
+ load_source_icon(256).save(
310
163
  WINDOWS_ICON_PATH,
311
164
  format="ICO",
312
165
  sizes=[(16, 16), (24, 24), (32, 32), (48, 48), (64, 64), (128, 128), (256, 256)],
@@ -317,26 +170,33 @@ def main() -> None:
317
170
  512: "Icon-512.png",
318
171
  }
319
172
  for size, filename in web_icon_sizes.items():
320
- copy_png(master, WEB_ICONS_DIR / filename, size)
321
- copy_png(master, WEB_ICONS_DIR / filename.replace("Icon-", "Icon-maskable-"), size)
322
- copy_png(light_master, WEB_ICONS_DIR / filename.replace(".png", "-light.png"), size)
323
- copy_png(light_master, WEB_ICONS_DIR / filename.replace("Icon-", "Icon-maskable-").replace(".png", "-light.png"), size)
324
- copy_png(master, SERVER_PUBLIC_ICONS_DIR / filename, size)
325
- copy_png(master, SERVER_PUBLIC_ICONS_DIR / filename.replace("Icon-", "Icon-maskable-"), size)
326
-
327
- copy_png(master, WEB_DIR / "favicon.png", 32)
328
- copy_png(master, SERVER_PUBLIC_DIR / "favicon.png", 32)
329
- write_favicon_svg(WEB_DIR / "favicon.svg")
330
- write_favicon_svg(WEB_DIR / "favicon_light.svg", light=True)
331
- write_favicon_svg(SERVER_PUBLIC_DIR / "favicon.svg")
332
- write_favicon_svg(SERVER_PUBLIC_DIR / "favicon_light.svg", light=True)
333
- write_favicon_svg(LANDING_LOGO_PATH, light=True)
334
- write_favicon_svg(EXTENSION_LOGO_PATH)
335
- copy_png(master, STATIC_IMG_DIR / "app_icon.png", 512)
336
- copy_png(light_master, STATIC_IMG_DIR / "app_icon_light.png", 512)
337
- copy_png(master, SERVER_PUBLIC_DIR / "assets" / "assets" / "branding" / "app_icon_256.png", 256)
338
- copy_png(tray, SERVER_PUBLIC_DIR / "assets" / "assets" / "branding" / "tray_icon_template.png", 64)
339
- copy_png(master, SERVER_PUBLIC_DIR / "assets" / "web" / "icons" / "Icon-192.png", 192)
173
+ save_icon(WEB_ICONS_DIR / filename, size)
174
+ save_icon(WEB_ICONS_DIR / filename.replace("Icon-", "Icon-maskable-"), size)
175
+ save_icon(WEB_ICONS_DIR / filename.replace(".png", "-light.png"), size)
176
+ save_icon(WEB_ICONS_DIR / filename.replace("Icon-", "Icon-maskable-").replace(".png", "-light.png"), size)
177
+ save_icon(SERVER_PUBLIC_ICONS_DIR / filename, size)
178
+ save_icon(SERVER_PUBLIC_ICONS_DIR / filename.replace("Icon-", "Icon-maskable-"), size)
179
+
180
+ save_icon(WEB_DIR / "favicon.png", 32)
181
+ save_icon(SERVER_PUBLIC_DIR / "favicon.png", 32)
182
+ write_source_svg(WEB_DIR / "favicon.svg")
183
+ write_source_svg(WEB_DIR / "favicon_light.svg")
184
+ write_source_svg(SERVER_PUBLIC_DIR / "favicon.svg")
185
+ write_source_svg(SERVER_PUBLIC_DIR / "favicon_light.svg")
186
+ write_source_svg(LANDING_LOGO_PATH)
187
+ write_source_svg(EXTENSION_LOGO_PATH)
188
+
189
+ for size in (16, 48, 128):
190
+ save_icon(EXTENSION_ICON_DIR / f"icon{size}.png", size)
191
+
192
+ save_icon(STATIC_IMG_DIR / "app_icon.png", 512)
193
+ save_icon(STATIC_IMG_DIR / "app_icon_light.png", 512)
194
+ save_icon(SERVER_PUBLIC_DIR / "assets" / "assets" / "branding" / "app_icon_256.png", 256)
195
+ make_tray_template(64).save(
196
+ SERVER_PUBLIC_DIR / "assets" / "assets" / "branding" / "tray_icon_template.png",
197
+ format="PNG",
198
+ )
199
+ save_icon(SERVER_PUBLIC_DIR / "assets" / "web" / "icons" / "Icon-192.png", 192)
340
200
 
341
201
  android_icon_sizes = {
342
202
  "mipmap-mdpi": 48,
@@ -346,7 +206,7 @@ def main() -> None:
346
206
  "mipmap-xxxhdpi": 192,
347
207
  }
348
208
  for folder, size in android_icon_sizes.items():
349
- copy_png(master, ANDROID_RES_DIR / folder / "ic_launcher.png", size)
209
+ save_icon(ANDROID_RES_DIR / folder / "ic_launcher.png", size)
350
210
 
351
211
 
352
212
  if __name__ == "__main__":
Binary file
@@ -1,22 +1,43 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="512" height="512" viewBox="0 0 100 100">
2
2
  <defs>
3
- <linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
4
- <stop offset="0%" stop-color="#9e8052"/>
5
- <stop offset="100%" stop-color="#439081"/>
3
+ <linearGradient id="tile" x1="0%" y1="0%" x2="100%" y2="100%">
4
+ <stop offset="0%" stop-color="#705331"></stop>
5
+ <stop offset="100%" stop-color="#22564c"></stop>
6
6
  </linearGradient>
7
- <radialGradient id="shine" cx="24%" cy="15%" r="70%">
8
- <stop offset="0%" stop-color="#fff4d8" stop-opacity="0.24"/>
9
- <stop offset="100%" stop-color="#fff4d8" stop-opacity="0"/>
7
+ <radialGradient id="shine" cx="26%" cy="14%" r="72%">
8
+ <stop offset="0%" stop-color="#ffffff" stop-opacity="0.22"></stop>
9
+ <stop offset="100%" stop-color="#ffffff" stop-opacity="0"></stop>
10
10
  </radialGradient>
11
+ <radialGradient id="core" cx="38%" cy="32%" r="75%">
12
+ <stop offset="0%" stop-color="#fffdf6"></stop>
13
+ <stop offset="48%" stop-color="#eee3cc"></stop>
14
+ <stop offset="100%" stop-color="#b5a888"></stop>
15
+ </radialGradient>
16
+ <radialGradient id="node" cx="36%" cy="30%" r="80%">
17
+ <stop offset="0%" stop-color="#f8dca8"></stop>
18
+ <stop offset="52%" stop-color="#d3a85f"></stop>
19
+ <stop offset="100%" stop-color="#9b6f2f"></stop>
20
+ </radialGradient>
21
+ <linearGradient id="tube" x1="0%" y1="0%" x2="0%" y2="100%">
22
+ <stop offset="0%" stop-color="#fffaf0"></stop>
23
+ <stop offset="52%" stop-color="#efe7d6"></stop>
24
+ <stop offset="100%" stop-color="#cabf9f"></stop>
25
+ </linearGradient>
26
+ <filter id="sh" x="-30%" y="-30%" width="160%" height="160%">
27
+ <feDropShadow dx="0" dy="1.1" stdDeviation="1.1" flood-color="#000000" flood-opacity="0.45"></feDropShadow>
28
+ </filter>
29
+ <clipPath id="tc"><rect x="0" y="0" width="100" height="100" rx="22.5"></rect></clipPath>
11
30
  </defs>
12
- <rect x="2.5" y="2.5" width="27" height="27" rx="9" ry="9" fill="url(#bg)" stroke="#ffffff" stroke-opacity="0.16" stroke-width="1"/>
13
- <rect x="2.5" y="2.5" width="27" height="27" rx="9" ry="9" fill="url(#shine)"/>
14
- <path d="M2.5 17h27v3.5c0 5-4 9-9 9h-9c-5 0-9-4-9-9Z" fill="#000000" opacity="0.08"/>
15
- <rect x="3" y="3" width="26" height="26" rx="8.5" ry="8.5" fill="none" stroke="#ffffff" stroke-opacity="0.18" stroke-width="1"/>
16
- <path d="M16 6.25 26.15 12.3 16 16.3 5.85 12.3Z" fill="#000000" opacity="0.20" transform="translate(0 0.65)"/>
17
- <path d="M16 14.75 25.85 19.45 16 22.25 6.15 19.45Z" fill="#000000" opacity="0.20" transform="translate(0 0.65)"/>
18
- <path d="M16 20.45 24.85 24.75 16 26.85 7.15 24.75Z" fill="#000000" opacity="0.20" transform="translate(0 0.65)"/>
19
- <path d="M16 5.7 26.8 12.1 16 16.5 5.2 12.1Z" fill="#ffffff"/>
20
- <path d="M16 14.2 26.5 19.3 16 22.4 5.5 19.3Z" fill="#ffffff"/>
21
- <path d="M16 20 25.4 24.6 16 27 6.6 24.6Z" fill="#ffffff"/>
22
- </svg>
31
+ <g clip-path="url(#tc)">
32
+ <rect x="0" y="0" width="100" height="100" fill="url(#tile)"></rect>
33
+ <rect x="0" y="0" width="100" height="100" fill="url(#shine)"></rect>
34
+ <g fill="none" stroke="url(#tube)" stroke-linecap="round" filter="url(#sh)">
35
+ <circle cx="50" cy="50" r="17" stroke-width="5" stroke-dasharray="78 29" transform="rotate(-35 50 50)" stroke-opacity="0.92"></circle>
36
+ <circle cx="50" cy="50" r="30" stroke-width="5" stroke-dasharray="150 39" transform="rotate(70 50 50)" stroke-opacity="0.8"></circle>
37
+ </g>
38
+ <circle cx="50" cy="50" r="7" fill="url(#core)"></circle>
39
+ <circle cx="50" cy="20" r="5.6" fill="url(#node)"></circle>
40
+ <circle cx="48" cy="18.4" r="1.7" fill="#fff7e6" fill-opacity="0.8"></circle>
41
+ </g>
42
+ <rect x="0.6" y="0.6" width="98.8" height="98.8" rx="22" fill="none" stroke="#ffffff" stroke-opacity="0.16" stroke-width="1.2"></rect>
43
+ </svg>
@@ -1,22 +1,43 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="512" height="512" viewBox="0 0 100 100">
2
2
  <defs>
3
- <linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
4
- <stop offset="0%" stop-color="#684e2c"/>
5
- <stop offset="100%" stop-color="#235c52"/>
3
+ <linearGradient id="tile" x1="0%" y1="0%" x2="100%" y2="100%">
4
+ <stop offset="0%" stop-color="#705331"></stop>
5
+ <stop offset="100%" stop-color="#22564c"></stop>
6
6
  </linearGradient>
7
- <radialGradient id="shine" cx="24%" cy="15%" r="70%">
8
- <stop offset="0%" stop-color="#ffffff" stop-opacity="0.20"/>
9
- <stop offset="100%" stop-color="#ffffff" stop-opacity="0"/>
7
+ <radialGradient id="shine" cx="26%" cy="14%" r="72%">
8
+ <stop offset="0%" stop-color="#ffffff" stop-opacity="0.22"></stop>
9
+ <stop offset="100%" stop-color="#ffffff" stop-opacity="0"></stop>
10
10
  </radialGradient>
11
+ <radialGradient id="core" cx="38%" cy="32%" r="75%">
12
+ <stop offset="0%" stop-color="#fffdf6"></stop>
13
+ <stop offset="48%" stop-color="#eee3cc"></stop>
14
+ <stop offset="100%" stop-color="#b5a888"></stop>
15
+ </radialGradient>
16
+ <radialGradient id="node" cx="36%" cy="30%" r="80%">
17
+ <stop offset="0%" stop-color="#f8dca8"></stop>
18
+ <stop offset="52%" stop-color="#d3a85f"></stop>
19
+ <stop offset="100%" stop-color="#9b6f2f"></stop>
20
+ </radialGradient>
21
+ <linearGradient id="tube" x1="0%" y1="0%" x2="0%" y2="100%">
22
+ <stop offset="0%" stop-color="#fffaf0"></stop>
23
+ <stop offset="52%" stop-color="#efe7d6"></stop>
24
+ <stop offset="100%" stop-color="#cabf9f"></stop>
25
+ </linearGradient>
26
+ <filter id="sh" x="-30%" y="-30%" width="160%" height="160%">
27
+ <feDropShadow dx="0" dy="1.1" stdDeviation="1.1" flood-color="#000000" flood-opacity="0.45"></feDropShadow>
28
+ </filter>
29
+ <clipPath id="tc"><rect x="0" y="0" width="100" height="100" rx="22.5"></rect></clipPath>
11
30
  </defs>
12
- <rect x="2.5" y="2.5" width="27" height="27" rx="9" ry="9" fill="url(#bg)" stroke="#000000" stroke-opacity="0.24" stroke-width="1"/>
13
- <rect x="2.5" y="2.5" width="27" height="27" rx="9" ry="9" fill="url(#shine)"/>
14
- <path d="M2.5 17h27v3.5c0 5-4 9-9 9h-9c-5 0-9-4-9-9Z" fill="#000000" opacity="0.12"/>
15
- <rect x="3" y="3" width="26" height="26" rx="8.5" ry="8.5" fill="none" stroke="#ffffff" stroke-opacity="0.18" stroke-width="1"/>
16
- <path d="M16 6.25 26.15 12.3 16 16.3 5.85 12.3Z" fill="#000000" opacity="0.20" transform="translate(0 0.65)"/>
17
- <path d="M16 14.75 25.85 19.45 16 22.25 6.15 19.45Z" fill="#000000" opacity="0.20" transform="translate(0 0.65)"/>
18
- <path d="M16 20.45 24.85 24.75 16 26.85 7.15 24.75Z" fill="#000000" opacity="0.20" transform="translate(0 0.65)"/>
19
- <path d="M16 5.7 26.8 12.1 16 16.5 5.2 12.1Z" fill="#fff9ed"/>
20
- <path d="M16 14.2 26.5 19.3 16 22.4 5.5 19.3Z" fill="#fff9ed"/>
21
- <path d="M16 20 25.4 24.6 16 27 6.6 24.6Z" fill="#fff9ed"/>
22
- </svg>
31
+ <g clip-path="url(#tc)">
32
+ <rect x="0" y="0" width="100" height="100" fill="url(#tile)"></rect>
33
+ <rect x="0" y="0" width="100" height="100" fill="url(#shine)"></rect>
34
+ <g fill="none" stroke="url(#tube)" stroke-linecap="round" filter="url(#sh)">
35
+ <circle cx="50" cy="50" r="17" stroke-width="5" stroke-dasharray="78 29" transform="rotate(-35 50 50)" stroke-opacity="0.92"></circle>
36
+ <circle cx="50" cy="50" r="30" stroke-width="5" stroke-dasharray="150 39" transform="rotate(70 50 50)" stroke-opacity="0.8"></circle>
37
+ </g>
38
+ <circle cx="50" cy="50" r="7" fill="url(#core)"></circle>
39
+ <circle cx="50" cy="20" r="5.6" fill="url(#node)"></circle>
40
+ <circle cx="48" cy="18.4" r="1.7" fill="#fff7e6" fill-opacity="0.8"></circle>
41
+ </g>
42
+ <rect x="0.6" y="0.6" width="98.8" height="98.8" rx="22" fill="none" stroke="#ffffff" stroke-opacity="0.16" stroke-width="1.2"></rect>
43
+ </svg>
Binary file
Binary file