@testgorilla/tgo-ui 8.11.4 → 8.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/components/icon/index.d.ts +1 -1
- package/components/inline-field/index.d.ts +2 -2
- package/fesm2022/testgorilla-tgo-ui-components-icon.mjs +25 -1
- package/fesm2022/testgorilla-tgo-ui-components-icon.mjs.map +1 -1
- package/mcp/catalog.json +1 -1
- package/mcp/server.mjs +128 -7
- package/package.json +1 -1
- package/projects/tgo-canopy-ui/assets/icons/rebrand/Corporate-filled.svg +3 -0
- package/projects/tgo-canopy-ui/assets/icons/rebrand/Corporate-in-line.svg +3 -0
- package/projects/tgo-canopy-ui/assets/icons/rebrand/Redeem-filled.svg +3 -0
- package/projects/tgo-canopy-ui/assets/icons/rebrand/Redeem-in-line.svg +3 -0
- package/projects/tgo-canopy-ui/assets/icons/rebrand/Rule-filled.svg +3 -0
- package/projects/tgo-canopy-ui/assets/icons/rebrand/Rule-in-line.svg +3 -0
- package/projects/tgo-canopy-ui/assets/icons/rebrand/Workspaces-filled.svg +3 -0
- package/projects/tgo-canopy-ui/assets/icons/rebrand/Workspaces-in-line.svg +3 -0
package/mcp/server.mjs
CHANGED
|
@@ -21634,7 +21634,7 @@ function registerListStoriesWithDesignLinksTool(server, store) {
|
|
|
21634
21634
|
function registerGetIconForFigmaNameTool(server, resolver) {
|
|
21635
21635
|
server.tool(
|
|
21636
21636
|
"get_icon_for_figma_name",
|
|
21637
|
-
'Resolve a Figma icon name (as exported by Figma Dev Mode) to a Canopy `<ui-icon>` name + svg path. Returns null when no match is found at any level. The `match` field tells you how the resolution happened: "exact" (after case/punctuation normalization), "alias" (
|
|
21637
|
+
'Resolve a Figma icon name (as exported by Figma Dev Mode, e.g. "Assessment/Timer") to a Canopy `<ui-icon>` name + svg path. The Figma "Category/" prefix is stripped automatically. Returns null when no match is found at any level. The `match` field tells you how the resolution happened: "mapped" (curated entry in mcp/icon-figma-map.json), "exact" (after prefix/case/punctuation normalization), "alias" (generic synonym in the same file), or "fuzzy" (substring match). The `confident` boolean is true for exact/alias and false for fuzzy \u2014 treat a non-confident result as "needs a human mapping decision" and verify visually before relying on it.',
|
|
21638
21638
|
{
|
|
21639
21639
|
figmaIconName: external_exports.string().describe('Icon name from Figma (e.g., "checkmark", "Arrow-down", "Eye Open"). Case- and punctuation-insensitive.')
|
|
21640
21640
|
},
|
|
@@ -21647,6 +21647,41 @@ function registerGetIconForFigmaNameTool(server, resolver) {
|
|
|
21647
21647
|
);
|
|
21648
21648
|
}
|
|
21649
21649
|
|
|
21650
|
+
// src/icons/icon-report.ts
|
|
21651
|
+
function buildIconNameReport(resolver, names) {
|
|
21652
|
+
const seen = /* @__PURE__ */ new Set();
|
|
21653
|
+
const unique = names.filter((n) => {
|
|
21654
|
+
const key = n.trim().toLowerCase();
|
|
21655
|
+
if (!key || seen.has(key)) return false;
|
|
21656
|
+
seen.add(key);
|
|
21657
|
+
return true;
|
|
21658
|
+
});
|
|
21659
|
+
const verdicts = unique.map((n) => resolver.classify(n));
|
|
21660
|
+
return {
|
|
21661
|
+
total: verdicts.length,
|
|
21662
|
+
confident: verdicts.filter((v) => v.status === "confident").length,
|
|
21663
|
+
knownGaps: verdicts.filter((v) => v.status === "known-gap").length,
|
|
21664
|
+
review: verdicts.filter((v) => v.status === "review")
|
|
21665
|
+
};
|
|
21666
|
+
}
|
|
21667
|
+
|
|
21668
|
+
// src/tools/check-icon-names.ts
|
|
21669
|
+
function registerCheckIconNamesTool(server, resolver) {
|
|
21670
|
+
server.tool(
|
|
21671
|
+
"check_icon_names",
|
|
21672
|
+
'Batch-audit icon names and return only the ones that need a human mapping decision. Input is a list of names \u2014 Figma export names (e.g. "Assessment/Timer") and/or free-form / natural-language icon words (e.g. "trash", "gear"). The response has counts for `confident` (safe to use) and `knownGaps` (intentionally no code icon \u2014 already decided), plus a `review` array of the actionable names: low-confidence fuzzy guesses and outright misses, each with a `reason`. Use this to flag unresolved icons for review rather than rendering a wrong guess. To resolve a single name to a concrete `<ui-icon>`, use get_icon_for_figma_name instead.',
|
|
21673
|
+
{
|
|
21674
|
+
names: external_exports.array(external_exports.string()).describe("Icon names to check (Figma export names and/or natural-language icon words).")
|
|
21675
|
+
},
|
|
21676
|
+
async ({ names }) => {
|
|
21677
|
+
const report = buildIconNameReport(resolver, names);
|
|
21678
|
+
return {
|
|
21679
|
+
content: [{ type: "text", text: JSON.stringify(report, null, 2) }]
|
|
21680
|
+
};
|
|
21681
|
+
}
|
|
21682
|
+
);
|
|
21683
|
+
}
|
|
21684
|
+
|
|
21650
21685
|
// src/tools/get-design-tokens.ts
|
|
21651
21686
|
function handleGetDesignTokens(tokens, params) {
|
|
21652
21687
|
if (!params.category) return tokens;
|
|
@@ -21708,41 +21743,113 @@ var IconResolver = class {
|
|
|
21708
21743
|
byNormalized = /* @__PURE__ */ new Map();
|
|
21709
21744
|
aliasMap;
|
|
21710
21745
|
unmapped;
|
|
21746
|
+
figmaMap;
|
|
21711
21747
|
icons;
|
|
21712
|
-
constructor(icons, aliases = {}, unmapped = []) {
|
|
21748
|
+
constructor(icons, aliases = {}, unmapped = [], figmaMap = {}) {
|
|
21713
21749
|
this.icons = icons;
|
|
21714
21750
|
for (const icon of icons) {
|
|
21715
21751
|
this.byNormalized.set(normalize(icon.name), icon);
|
|
21716
21752
|
}
|
|
21753
|
+
for (const icon of icons) {
|
|
21754
|
+
const base = normalize(stripVariantSuffix(icon.name));
|
|
21755
|
+
if (!this.byNormalized.has(base)) {
|
|
21756
|
+
this.byNormalized.set(base, icon);
|
|
21757
|
+
}
|
|
21758
|
+
}
|
|
21717
21759
|
this.aliasMap = /* @__PURE__ */ new Map();
|
|
21718
21760
|
for (const [from, to] of Object.entries(aliases)) {
|
|
21719
21761
|
this.aliasMap.set(normalize(from), to);
|
|
21720
21762
|
}
|
|
21721
21763
|
this.unmapped = new Set(unmapped.map(normalize));
|
|
21764
|
+
this.figmaMap = /* @__PURE__ */ new Map();
|
|
21765
|
+
for (const [figmaName, entry] of Object.entries(figmaMap)) {
|
|
21766
|
+
this.figmaMap.set(normalize(figmaName), entry);
|
|
21767
|
+
}
|
|
21722
21768
|
}
|
|
21723
21769
|
resolve(figmaName) {
|
|
21724
|
-
const
|
|
21770
|
+
const curated = this.figmaMap.get(normalize(figmaName));
|
|
21771
|
+
if (curated) {
|
|
21772
|
+
if (curated.status === "mapped" && curated.canopy) {
|
|
21773
|
+
const target = this.byNormalized.get(normalize(curated.canopy));
|
|
21774
|
+
if (target) {
|
|
21775
|
+
return { canopyIconName: target.name, svgPath: target.svgPath, match: "mapped", confident: true };
|
|
21776
|
+
}
|
|
21777
|
+
}
|
|
21778
|
+
return null;
|
|
21779
|
+
}
|
|
21780
|
+
const normalized = normalize(stripCategoryPrefix(figmaName));
|
|
21725
21781
|
if (!normalized) return null;
|
|
21726
21782
|
const exact = this.byNormalized.get(normalized);
|
|
21727
21783
|
if (exact) {
|
|
21728
|
-
return { canopyIconName: exact.name, svgPath: exact.svgPath, match: "exact" };
|
|
21784
|
+
return { canopyIconName: exact.name, svgPath: exact.svgPath, match: "exact", confident: true };
|
|
21729
21785
|
}
|
|
21730
21786
|
const aliasTarget = this.aliasMap.get(normalized);
|
|
21731
21787
|
if (aliasTarget) {
|
|
21732
21788
|
const target = this.byNormalized.get(normalize(aliasTarget));
|
|
21733
21789
|
if (target) {
|
|
21734
|
-
return { canopyIconName: target.name, svgPath: target.svgPath, match: "alias" };
|
|
21790
|
+
return { canopyIconName: target.name, svgPath: target.svgPath, match: "alias", confident: true };
|
|
21735
21791
|
}
|
|
21736
21792
|
}
|
|
21737
21793
|
if (this.unmapped.has(normalized)) return null;
|
|
21738
21794
|
if (normalized.length >= MIN_FUZZY_QUERY_LENGTH) {
|
|
21739
21795
|
const best = this.bestFuzzyMatch(normalized);
|
|
21740
21796
|
if (best) {
|
|
21741
|
-
return { canopyIconName: best.name, svgPath: best.svgPath, match: "fuzzy" };
|
|
21797
|
+
return { canopyIconName: best.name, svgPath: best.svgPath, match: "fuzzy", confident: false };
|
|
21742
21798
|
}
|
|
21743
21799
|
}
|
|
21744
21800
|
return null;
|
|
21745
21801
|
}
|
|
21802
|
+
/**
|
|
21803
|
+
* Classify a name for Layer-1 reporting: is it safe to use, does it need a
|
|
21804
|
+
* human mapping decision, or is it an already-decided gap? Used by
|
|
21805
|
+
* `check_icon_names` to surface only the names worth a human's attention —
|
|
21806
|
+
* works for Figma export names AND free-form / natural-language icon words.
|
|
21807
|
+
*/
|
|
21808
|
+
classify(figmaName) {
|
|
21809
|
+
const curated = this.figmaMap.get(normalize(figmaName));
|
|
21810
|
+
if (curated) {
|
|
21811
|
+
if (curated.status === "mapped" && curated.canopy) {
|
|
21812
|
+
const target = this.byNormalized.get(normalize(curated.canopy));
|
|
21813
|
+
if (target) {
|
|
21814
|
+
return {
|
|
21815
|
+
name: figmaName,
|
|
21816
|
+
status: "confident",
|
|
21817
|
+
match: "mapped",
|
|
21818
|
+
canopyIconName: target.name,
|
|
21819
|
+
svgPath: target.svgPath,
|
|
21820
|
+
reason: "curated map"
|
|
21821
|
+
};
|
|
21822
|
+
}
|
|
21823
|
+
}
|
|
21824
|
+
const reason = curated.status === "figma-only" ? "Figma-only by design (no code icon)" : curated.status === "add-to-canopy" ? "not built in Canopy yet" : "curated entry has no resolvable target";
|
|
21825
|
+
return { name: figmaName, status: "known-gap", canopyIconName: null, svgPath: null, reason };
|
|
21826
|
+
}
|
|
21827
|
+
const r = this.resolve(figmaName);
|
|
21828
|
+
if (r && r.confident) {
|
|
21829
|
+
return {
|
|
21830
|
+
name: figmaName,
|
|
21831
|
+
status: "confident",
|
|
21832
|
+
match: r.match,
|
|
21833
|
+
canopyIconName: r.canopyIconName,
|
|
21834
|
+
svgPath: r.svgPath,
|
|
21835
|
+
reason: r.match
|
|
21836
|
+
};
|
|
21837
|
+
}
|
|
21838
|
+
if (r && r.match === "fuzzy") {
|
|
21839
|
+
return {
|
|
21840
|
+
name: figmaName,
|
|
21841
|
+
status: "review",
|
|
21842
|
+
match: "fuzzy",
|
|
21843
|
+
canopyIconName: r.canopyIconName,
|
|
21844
|
+
svgPath: r.svgPath,
|
|
21845
|
+
reason: `low-confidence guess (${r.canopyIconName}) \u2014 verify or add a mapping`
|
|
21846
|
+
};
|
|
21847
|
+
}
|
|
21848
|
+
if (this.unmapped.has(normalize(stripCategoryPrefix(figmaName)))) {
|
|
21849
|
+
return { name: figmaName, status: "known-gap", canopyIconName: null, svgPath: null, reason: "no Canopy equivalent (unmapped)" };
|
|
21850
|
+
}
|
|
21851
|
+
return { name: figmaName, status: "review", canopyIconName: null, svgPath: null, reason: "no match found \u2014 needs a mapping or a new icon" };
|
|
21852
|
+
}
|
|
21746
21853
|
/**
|
|
21747
21854
|
* Pick the best fuzzy candidate rather than the first one in iteration order.
|
|
21748
21855
|
* Among icons whose normalized name contains (or is contained by) the query,
|
|
@@ -21773,6 +21880,13 @@ function compareFuzzyRank(a, b) {
|
|
|
21773
21880
|
function stripSvgExtension(name) {
|
|
21774
21881
|
return name.toLowerCase().endsWith(".svg") ? name.slice(0, -".svg".length) : name;
|
|
21775
21882
|
}
|
|
21883
|
+
function stripCategoryPrefix(name) {
|
|
21884
|
+
const slash = name.lastIndexOf("/");
|
|
21885
|
+
return slash >= 0 ? name.slice(slash + 1) : name;
|
|
21886
|
+
}
|
|
21887
|
+
function stripVariantSuffix(name) {
|
|
21888
|
+
return name.replace(/-(filled|in-line)$/i, "");
|
|
21889
|
+
}
|
|
21776
21890
|
function normalize(name) {
|
|
21777
21891
|
return stripSvgExtension(name).toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
21778
21892
|
}
|
|
@@ -21796,6 +21910,12 @@ var CatalogSchema = external_exports.object({
|
|
|
21796
21910
|
icons: external_exports.array(external_exports.object({ name: external_exports.string(), svgPath: external_exports.string() })).optional().default([]),
|
|
21797
21911
|
iconAliases: external_exports.record(external_exports.string()).optional().default({}),
|
|
21798
21912
|
iconUnmapped: external_exports.array(external_exports.string()).optional().default([]),
|
|
21913
|
+
iconFigmaMap: external_exports.record(external_exports.object({
|
|
21914
|
+
canopy: external_exports.string().nullable(),
|
|
21915
|
+
node: external_exports.string().optional(),
|
|
21916
|
+
status: external_exports.enum(["mapped", "figma-only", "add-to-canopy"]),
|
|
21917
|
+
note: external_exports.string().optional()
|
|
21918
|
+
})).optional().default({}),
|
|
21799
21919
|
tokens: external_exports.array(external_exports.object({ name: external_exports.string(), value: external_exports.string(), category: external_exports.string() })).optional().default([]),
|
|
21800
21920
|
// Foundations additions (Phase G.1.d). Same default-to-empty pattern.
|
|
21801
21921
|
typography: external_exports.array(external_exports.object({
|
|
@@ -21830,8 +21950,9 @@ function createStaticMcpServer(catalog) {
|
|
|
21830
21950
|
registerGetComponentTypesTool(server, store);
|
|
21831
21951
|
registerGetQueryGuideTool(server, store);
|
|
21832
21952
|
registerListStoriesWithDesignLinksTool(server, store);
|
|
21833
|
-
const iconResolver = new IconResolver(catalog.icons ?? [], catalog.iconAliases ?? {}, catalog.iconUnmapped ?? []);
|
|
21953
|
+
const iconResolver = new IconResolver(catalog.icons ?? [], catalog.iconAliases ?? {}, catalog.iconUnmapped ?? [], catalog.iconFigmaMap ?? {});
|
|
21834
21954
|
registerGetIconForFigmaNameTool(server, iconResolver);
|
|
21955
|
+
registerCheckIconNamesTool(server, iconResolver);
|
|
21835
21956
|
registerGetDesignTokensTool(server, catalog.tokens ?? []);
|
|
21836
21957
|
registerListTypographyClassesTool(server, catalog.typography ?? []);
|
|
21837
21958
|
registerListColorPalettesTool(server, catalog.colorPalettes ?? []);
|
package/package.json
CHANGED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<path d="M2 21V3H12V7H22V21H2ZM4 19H10V17H4V19ZM4 15H10V13H4V15ZM4 11H10V9H4V11ZM4 7H10V5H4V7ZM12 19H20V9H12V19ZM14 13V11H18V13H14ZM14 17V15H18V17H14Z" fill="currentColor"/>
|
|
3
|
+
</svg>
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<path d="M2 21V3H12V7H22V21H2ZM4 19H10V17H4V19ZM4 15H10V13H4V15ZM4 11H10V9H4V11ZM4 7H10V5H4V7ZM12 19H20V9H12V19ZM14 13V11H18V13H14ZM14 17V15H18V17H14Z" fill="currentColor"/>
|
|
3
|
+
</svg>
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<path d="M4 17V19H20V17H4ZM2 6H6.2C6.11667 5.85 6.0625 5.69167 6.0375 5.525C6.0125 5.35833 6 5.18333 6 5C6 4.16667 6.29167 3.45833 6.875 2.875C7.45833 2.29167 8.16667 2 9 2C9.5 2 9.9625 2.12917 10.3875 2.3875C10.8125 2.64583 11.1833 2.96667 11.5 3.35L12 4L12.5 3.35C12.8 2.95 13.1667 2.625 13.6 2.375C14.0333 2.125 14.5 2 15 2C15.8333 2 16.5417 2.29167 17.125 2.875C17.7083 3.45833 18 4.16667 18 5C18 5.18333 17.9875 5.35833 17.9625 5.525C17.9375 5.69167 17.8833 5.85 17.8 6H22V21H2V6ZM4 14H20V8H14.9L17 10.85L15.4 12L12 7.4L8.6 12L7 10.85L9.05 8H4V14ZM9.7125 5.7125C9.90417 5.52083 10 5.28333 10 5C10 4.71667 9.90417 4.47917 9.7125 4.2875C9.52083 4.09583 9.28333 4 9 4C8.71667 4 8.47917 4.09583 8.2875 4.2875C8.09583 4.47917 8 4.71667 8 5C8 5.28333 8.09583 5.52083 8.2875 5.7125C8.47917 5.90417 8.71667 6 9 6C9.28333 6 9.52083 5.90417 9.7125 5.7125ZM15 6C15.2833 6 15.5208 5.90417 15.7125 5.7125C15.9042 5.52083 16 5.28333 16 5C16 4.71667 15.9042 4.47917 15.7125 4.2875C15.5208 4.09583 15.2833 4 15 4C14.7167 4 14.4792 4.09583 14.2875 4.2875C14.0958 4.47917 14 4.71667 14 5C14 5.28333 14.0958 5.52083 14.2875 5.7125C14.4792 5.90417 14.7167 6 15 6Z" fill="currentColor"/>
|
|
3
|
+
</svg>
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<path d="M4 17V19H20V17H4ZM2 6H6.2C6.11667 5.85 6.0625 5.69167 6.0375 5.525C6.0125 5.35833 6 5.18333 6 5C6 4.16667 6.29167 3.45833 6.875 2.875C7.45833 2.29167 8.16667 2 9 2C9.5 2 9.9625 2.12917 10.3875 2.3875C10.8125 2.64583 11.1833 2.96667 11.5 3.35L12 4L12.5 3.35C12.8 2.95 13.1667 2.625 13.6 2.375C14.0333 2.125 14.5 2 15 2C15.8333 2 16.5417 2.29167 17.125 2.875C17.7083 3.45833 18 4.16667 18 5C18 5.18333 17.9875 5.35833 17.9625 5.525C17.9375 5.69167 17.8833 5.85 17.8 6H22V21H2V6ZM4 14H20V8H14.9L17 10.85L15.4 12L12 7.4L8.6 12L7 10.85L9.05 8H4V14ZM9.7125 5.7125C9.90417 5.52083 10 5.28333 10 5C10 4.71667 9.90417 4.47917 9.7125 4.2875C9.52083 4.09583 9.28333 4 9 4C8.71667 4 8.47917 4.09583 8.2875 4.2875C8.09583 4.47917 8 4.71667 8 5C8 5.28333 8.09583 5.52083 8.2875 5.7125C8.47917 5.90417 8.71667 6 9 6C9.28333 6 9.52083 5.90417 9.7125 5.7125ZM15 6C15.2833 6 15.5208 5.90417 15.7125 5.7125C15.9042 5.52083 16 5.28333 16 5C16 4.71667 15.9042 4.47917 15.7125 4.2875C15.5208 4.09583 15.2833 4 15 4C14.7167 4 14.4792 4.09583 14.2875 4.2875C14.0958 4.47917 14 4.71667 14 5C14 5.28333 14.0958 5.52083 14.2875 5.7125C14.4792 5.90417 14.7167 6 15 6Z" fill="currentColor"/>
|
|
3
|
+
</svg>
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<path d="M14.4 19.9998L13 18.5998L15.6 15.9998L13 13.3998L14.4 11.9998L17 14.5998L19.6 11.9998L21 13.3998L18.4 15.9998L21 18.5998L19.6 19.9998L17 17.3998L14.4 19.9998ZM16.375 10.9998L12.825 7.4498L14.225 6.0498L16.35 8.1748L20.6 3.9248L22 5.3498L16.375 10.9998ZM2 16.9998V14.9998H11V16.9998H2ZM2 8.9998V6.9998H11V8.9998H2Z" fill="currentColor"/>
|
|
3
|
+
</svg>
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<path d="M14.4 19.9998L13 18.5998L15.6 15.9998L13 13.3998L14.4 11.9998L17 14.5998L19.6 11.9998L21 13.3998L18.4 15.9998L21 18.5998L19.6 19.9998L17 17.3998L14.4 19.9998ZM16.375 10.9998L12.825 7.4498L14.225 6.0498L16.35 8.1748L20.6 3.9248L22 5.3498L16.375 10.9998ZM2 16.9998V14.9998H11V16.9998H2ZM2 8.9998V6.9998H11V8.9998H2Z" fill="currentColor"/>
|
|
3
|
+
</svg>
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<path d="M3.175 19.825C2.39167 19.0417 2 18.1 2 17C2 15.9 2.39167 14.9583 3.175 14.175C3.95833 13.3917 4.9 13 6 13C7.1 13 8.04167 13.3917 8.825 14.175C9.60833 14.9583 10 15.9 10 17C10 18.1 9.60833 19.0417 8.825 19.825C8.04167 20.6083 7.1 21 6 21C4.9 21 3.95833 20.6083 3.175 19.825ZM15.175 19.825C14.3917 19.0417 14 18.1 14 17C14 15.9 14.3917 14.9583 15.175 14.175C15.9583 13.3917 16.9 13 18 13C19.1 13 20.0417 13.3917 20.825 14.175C21.6083 14.9583 22 15.9 22 17C22 18.1 21.6083 19.0417 20.825 19.825C20.0417 20.6083 19.1 21 18 21C16.9 21 15.9583 20.6083 15.175 19.825ZM9.175 9.825C8.39167 9.04167 8 8.1 8 7C8 5.9 8.39167 4.95833 9.175 4.175C9.95833 3.39167 10.9 3 12 3C13.1 3 14.0417 3.39167 14.825 4.175C15.6083 4.95833 16 5.9 16 7C16 8.1 15.6083 9.04167 14.825 9.825C14.0417 10.6083 13.1 11 12 11C10.9 11 9.95833 10.6083 9.175 9.825Z" fill="currentColor"/>
|
|
3
|
+
</svg>
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<path d="M3.175 19.825C2.39167 19.0417 2 18.1 2 17C2 15.9 2.39167 14.9583 3.175 14.175C3.95833 13.3917 4.9 13 6 13C7.1 13 8.04167 13.3917 8.825 14.175C9.60833 14.9583 10 15.9 10 17C10 18.1 9.60833 19.0417 8.825 19.825C8.04167 20.6083 7.1 21 6 21C4.9 21 3.95833 20.6083 3.175 19.825ZM15.175 19.825C14.3917 19.0417 14 18.1 14 17C14 15.9 14.3917 14.9583 15.175 14.175C15.9583 13.3917 16.9 13 18 13C19.1 13 20.0417 13.3917 20.825 14.175C21.6083 14.9583 22 15.9 22 17C22 18.1 21.6083 19.0417 20.825 19.825C20.0417 20.6083 19.1 21 18 21C16.9 21 15.9583 20.6083 15.175 19.825ZM7.4125 18.4125C7.80417 18.0208 8 17.55 8 17C8 16.45 7.80417 15.9792 7.4125 15.5875C7.02083 15.1958 6.55 15 6 15C5.45 15 4.97917 15.1958 4.5875 15.5875C4.19583 15.9792 4 16.45 4 17C4 17.55 4.19583 18.0208 4.5875 18.4125C4.97917 18.8042 5.45 19 6 19C6.55 19 7.02083 18.8042 7.4125 18.4125ZM19.4125 18.4125C19.8042 18.0208 20 17.55 20 17C20 16.45 19.8042 15.9792 19.4125 15.5875C19.0208 15.1958 18.55 15 18 15C17.45 15 16.9792 15.1958 16.5875 15.5875C16.1958 15.9792 16 16.45 16 17C16 17.55 16.1958 18.0208 16.5875 18.4125C16.9792 18.8042 17.45 19 18 19C18.55 19 19.0208 18.8042 19.4125 18.4125ZM9.175 9.825C8.39167 9.04167 8 8.1 8 7C8 5.9 8.39167 4.95833 9.175 4.175C9.95833 3.39167 10.9 3 12 3C13.1 3 14.0417 3.39167 14.825 4.175C15.6083 4.95833 16 5.9 16 7C16 8.1 15.6083 9.04167 14.825 9.825C14.0417 10.6083 13.1 11 12 11C10.9 11 9.95833 10.6083 9.175 9.825ZM13.4125 8.4125C13.8042 8.02083 14 7.55 14 7C14 6.45 13.8042 5.97917 13.4125 5.5875C13.0208 5.19583 12.55 5 12 5C11.45 5 10.9792 5.19583 10.5875 5.5875C10.1958 5.97917 10 6.45 10 7C10 7.55 10.1958 8.02083 10.5875 8.4125C10.9792 8.80417 11.45 9 12 9C12.55 9 13.0208 8.80417 13.4125 8.4125Z" fill="currentColor"/>
|
|
3
|
+
</svg>
|