authorgravatar for maria@kuuro.netmaria <maria@kuuro.net> 2026-10-14 20:51:07+00:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-10-14 20:51:07+00:00
log348f217a853dd4a23d7fa4834dedb05f545c2075
treef5b725829b4c289fc96d9b4c613c66df3fca1d4b
parente47bfe4617f6fdca2c6513bd0afe0f6b8d24688a
signature Signed by PGP key B5690EEEBB952194

fix(web,mobile): muse code uses meta's official blue logo (#19562)


5 files changed, 102 insertions(+), 13 deletions(-)

apps/mobile/src/components/ProviderIcon.tsx+28-4
......@@ -1,8 +1,8 @@
11import { Image } from "expo-image";
2import { Path, Svg } from "react-native-svg";
2import { Defs, LinearGradient, Path, Stop, Svg } from "react-native-svg";
33import { View } from "react-native";
44import { providerInstanceInitials } from "@t3tools/client-runtime/state/provider-instance-display";
5import { useState } from "react";
5import { useId, useState } from "react";
66import { resolveOfficialAcpRegistryIconUrl } from "@t3tools/contracts";
77import { useAppearancePreferences } from "../features/settings/appearance/AppearancePreferencesProvider";
88import { AppText as Text } from "./AppText";
......@@ -66,6 +66,7 @@ function AcpRegistryProviderIcon(props: {
6666export function ProviderIcon(props: ProviderIconProps) {
6767 const { themeAppearance } = useAppearancePreferences();
6868 const isDarkMode = themeAppearance === "dark";
69 const gradientId = useId();
6970 const size = props.size ?? 16;
7071 const mono = isDarkMode ? "#e5e5e5" : "#171717";
7172
......@@ -99,12 +100,35 @@ export function ProviderIcon(props: ProviderIconProps) {
99100 isDarkMode ? fill.dark : fill.light;
100101 return (
101102 <Svg width={size} height={size} viewBox={packageIcon.viewBox} fill="none">
102 {packageIcon.paths.map((path) => (
103 <Defs>
104 {packageIcon.paths.map((path, index) =>
105 path.gradient ? (
106 <LinearGradient
107 key={path.d}
108 id={`${gradientId}-${index}`}
109 x1={path.gradient.x1}
110 y1={path.gradient.y1}
111 x2={path.gradient.x2}
112 y2={path.gradient.y2}
113 gradientUnits="userSpaceOnUse"
114 >
115 {path.gradient.stops.map((stop) => (
116 <Stop key={stop.offset} offset={stop.offset} stopColor={stop.color} />
117 ))}
118 </LinearGradient>
119 ) : null,
120 )}
121 </Defs>
122 {packageIcon.paths.map((path, index) => (
103123 <Path
104124 key={path.d}
105125 d={path.d}
106126 fillRule={path.fillRule}
107 fill={themeFill(path.fill ?? packageIcon.fill)}
127 fill={
128 path.gradient
129 ? `url(#${gradientId}-${index})`
130 : themeFill(path.fill ?? packageIcon.fill)
131 }
108132 />
109133 ))}
110134 </Svg>
apps/web/src/components/chat/ChatComposer.tsx+2-1
......@@ -5649,7 +5649,8 @@ export const ChatComposer = memo(function ChatComposer(props: ChatComposerProps)
56495649 activeProviderIconClassName: cn(
56505650 composerProviderState.modelPickerIconClassName,
56515651 composerControlsCollapsed &&
5652 "fill-muted-foreground/70! text-muted-foreground/70! [&_path]:fill-muted-foreground/70! [&_rect]:fill-muted-foreground/70! [&_[data-icon-detail]]:fill-transparent!",
5652 // Package glyphs get opaque fills and one opacity, so overlapping paths don't band.
5653 "fill-muted-foreground/70! text-muted-foreground/70! [&_path]:fill-muted-foreground/70! [&_rect]:fill-muted-foreground/70! [&_[data-icon-detail]]:fill-transparent! [&[data-provider-package-icon]]:opacity-70 [&[data-provider-package-icon]_path:not([data-icon-detail])]:fill-muted-foreground!",
56535654 ),
56545655 }
56555656 : {})}
apps/web/src/components/chat/ProviderPackageIcon.tsx+28-2
......@@ -1,4 +1,4 @@
1import type { CSSProperties, SVGProps } from "react";
1import { useId, type CSSProperties, type SVGProps } from "react";
22
33import type { ProviderIcon } from "@t3tools/provider-core/client";
44
......@@ -13,11 +13,14 @@ export function ProviderPackageIcon({
1313 className,
1414 ...props
1515}: { readonly icon: ProviderIcon } & SVGProps<SVGSVGElement>) {
16 const gradientId = useId();
1617 return (
1718 <svg
1819 {...props}
1920 viewBox={icon.viewBox}
2021 fill="none"
22 // Lets monochrome renderings dim the whole glyph once instead of each path.
23 data-provider-package-icon
2124 className={cn("fill-(--icon-light) dark:fill-(--icon-dark)", className)}
2225 style={
2326 {
......@@ -26,11 +29,34 @@ export function ProviderPackageIcon({
2629 } as CSSProperties
2730 }
2831 >
29 {icon.paths.map((path) => (
32 {icon.paths.some((path) => path.gradient) ? (
33 <defs>
34 {icon.paths.map((path, index) =>
35 path.gradient ? (
36 <linearGradient
37 key={path.d}
38 id={`${gradientId}-${index}`}
39 x1={path.gradient.x1}
40 y1={path.gradient.y1}
41 x2={path.gradient.x2}
42 y2={path.gradient.y2}
43 gradientUnits="userSpaceOnUse"
44 >
45 {path.gradient.stops.map((stop) => (
46 <stop key={stop.offset} offset={stop.offset} stopColor={stop.color} />
47 ))}
48 </linearGradient>
49 ) : null,
50 )}
51 </defs>
52 ) : null}
53 {icon.paths.map((path, index) => (
3054 <path
3155 key={path.d}
3256 d={path.d}
3357 fillRule={path.fillRule}
58 // An attribute, so monochrome renderings can still override it from CSS.
59 fill={path.gradient ? `url(#${gradientId}-${index})` : undefined}
3460 // Monochrome renderings (the collapsed composer) clear these detail paths.
3561 data-icon-detail={path.fill ? true : undefined}
3662 className={path.fill ? "fill-(--path-light) dark:fill-(--path-dark)" : undefined}
packages/provider-core/src/client.ts+12-2
......@@ -33,8 +33,8 @@ export interface ProviderEnvironmentField {
3333
3434/**
3535 * A provider glyph as plain data, so web and mobile can each draw it with
36 * their own SVG renderer. Colors are per theme; a path without a fill uses
37 * the icon's `fill`.
36 * their own SVG renderer. Colors are per theme; a path without a fill or
37 * gradient uses the icon's `fill`.
3838 */
3939export interface ProviderIcon {
4040 readonly viewBox: string;
......@@ -43,9 +43,19 @@ export interface ProviderIcon {
4343 readonly d: string;
4444 readonly fillRule?: "evenodd" | "nonzero";
4545 readonly fill?: { readonly light: string; readonly dark: string };
46 /** A brand gradient, the same in both themes. Coordinates are in viewBox units. */
47 readonly gradient?: ProviderIconGradient;
4648 }>;
4749}
4850
51export interface ProviderIconGradient {
52 readonly x1: number;
53 readonly y1: number;
54 readonly x2: number;
55 readonly y2: number;
56 readonly stops: ReadonlyArray<{ readonly offset: number; readonly color: string }>;
57}
58
4959export interface ProviderClientDefinition {
5060 readonly driverKind: ProviderDriverKind;
5161 readonly label: string;
packages/provider-muse/src/client.ts+32-4
......@@ -14,13 +14,41 @@ export const museClient = defineProviderClient({
1414 label: "Muse Code",
1515 settingsSchema: MuseSettings,
1616 badgeLabel: "Beta",
17 // Meta's symbol (https://commons.wikimedia.org/wiki/File:Meta_Platforms_Inc._logo_(cropped).svg).
1718 icon: {
18 viewBox: "0 0 150.4828 100",
19 fill: { light: "#171717", dark: "#e5e5e5" },
19 viewBox: "0 0 287.56 191",
20 fill: { light: "#0081fb", dark: "#0081fb" },
2021 paths: [
2122 {
22 d: "M107.9999847,0.0000013c-12.3391113,0-21.984787,9.2935991-30.7164001,21.0993118 C65.2847366,5.821527,55.2499847,0,43.2413788,0C18.7586193,0,0,31.8620682,0,65.5862122 C0,86.6896515,10.2095623,100,27.3103466,100c12.3080502,0,21.1600361-5.8025894,36.8965454-33.3103409 c0,0,6.5597382-11.5841255,11.0725021-19.563858c1.5813522,2.5531845,3.2431107,5.3001404,4.9964676,8.2535095 l7.379303,12.4137955C102.0298843,91.8478851,110.039032,100,124.5517273,100 c16.6595764,0,25.9310303-13.4923325,25.9310303-35.0344849 C150.4827576,29.6551723,131.301178,0.0000013,107.9999847,0.0000013z M52.2068977,59.2413788 c-12.7586212,20-17.1724167,24.4827576-24.2758656,24.4827576c-7.3103428,0-11.6551704-6.4178314-11.6551704-17.8620682 c0-24.4827576,12.2068977-49.5172424,26.7586231-49.5172424c7.880127,0,14.4653816,4.5510426,24.5522308,18.9913158 C58.0087967,50.0272293,52.2068977,59.2413788,52.2068977,59.2413788z M100.3597336,56.7235756L91.5367355,42.00877 c-2.3876724-3.8832092-4.6757278-7.451458-6.8838348-10.7230263 c7.951973-12.273531,14.5113449-18.3891907,22.3126144-18.3891907c16.2069016,0,29.1724243,23.8620682,29.1724243,53.1724091 c0,11.1724167-3.6593475,17.6551743-11.2413864,17.6551743 C117.6294937,83.7241364,114.1578674,78.924736,100.3597336,56.7235756z",
23 fillRule: "evenodd",
23 d: "m31.06,125.96c0,10.98 2.41,19.41 5.56,24.51 4.13,6.68 10.29,9.51 16.57,9.51 8.1,0 15.51-2.01 29.79-21.76 11.44-15.83 24.92-38.05 33.99-51.98l15.36-23.6c10.67-16.39 23.02-34.61 37.18-46.96 11.56-10.08 24.03-15.68 36.58-15.68 21.07,0 41.14,12.21 56.5,35.11 16.81,25.08 24.97,56.67 24.97,89.27 0,19.38-3.82,33.62-10.32,44.87-6.28,10.88-18.52,21.75-39.11,21.75l0-31.02c17.63,0 22.03-16.2 22.03-34.74 0-26.42-6.16-55.74-19.73-76.69-9.63-14.86-22.11-23.94-35.84-23.94-14.85,0-26.8,11.2-40.23,31.17-7.14,10.61-14.47,23.54-22.7,38.13l-9.06,16.05c-18.2,32.27-22.81,39.62-31.91,51.75-15.95,21.24-29.57,29.29-47.5,29.29-21.27,0-34.72-9.21-43.05-23.09-6.8-11.31-10.14-26.15-10.14-43.06z",
24 },
25 {
26 d: "m24.49,37.3c14.24-21.95 34.79-37.3 58.36-37.3 13.65,0 27.22,4.04 41.39,15.61 15.5,12.65 32.02,33.48 52.63,67.81l7.39,12.32c17.84,29.72 27.99,45.01 33.93,52.22 7.64,9.26 12.99,12.02 19.94,12.02 17.63,0 22.03-16.2 22.03-34.74l27.4-.86c0,19.38-3.82,33.62-10.32,44.87-6.28,10.88-18.52,21.75-39.11,21.75-12.8,0-24.14-2.78-36.68-14.61-9.64-9.08-20.91-25.21-29.58-39.71l-25.79-43.08c-12.94-21.62-24.81-37.74-31.68-45.04-7.39-7.85-16.89-17.33-32.05-17.33-12.27,0-22.69,8.61-31.41,21.78z",
27 gradient: {
28 x1: 61,
29 y1: 117,
30 x2: 259,
31 y2: 127,
32 stops: [
33 { offset: 0, color: "#0064e1" },
34 { offset: 0.4, color: "#0064e1" },
35 { offset: 0.83, color: "#0073ee" },
36 { offset: 1, color: "#0082fb" },
37 ],
38 },
39 },
40 {
41 d: "m82.35,31.23c-12.27,0-22.69,8.61-31.41,21.78-12.33,18.61-19.88,46.33-19.88,72.95 0,10.98 2.41,19.41 5.56,24.51l-26.48,17.44c-6.8-11.31-10.14-26.15-10.14-43.06 0-30.75 8.44-62.8 24.49-87.55 14.24-21.95 34.79-37.3 58.36-37.3z",
42 gradient: {
43 x1: 45,
44 y1: 139,
45 x2: 45,
46 y2: 66,
47 stops: [
48 { offset: 0, color: "#0082fb" },
49 { offset: 1, color: "#0064e0" },
50 ],
51 },
2452 },
2553 ],
2654 },