@tanstack/devtools 0.6.23 → 0.6.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.
- package/dist/dev.js +1 -1
- package/dist/devtools/{MBQPV7BO.js → OBIHU6L6.js} +131 -27
- package/dist/devtools/{YRFZDV5N.js → UUNAZSBD.js} +180 -52
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/src/styles/use-styles.ts +69 -0
- package/src/tabs/marketplace/plugin-section.tsx +52 -0
- package/src/tabs/marketplace/plugin-utils.test.ts +22 -14
- package/src/tabs/marketplace/plugin-utils.ts +14 -15
- package/src/tabs/plugin-registry.ts +29 -0
package/dist/dev.js
CHANGED
|
@@ -30,7 +30,7 @@ var TanStackDevtoolsCore = class {
|
|
|
30
30
|
const mountTo = el;
|
|
31
31
|
const dispose = render(() => {
|
|
32
32
|
const _self$ = this;
|
|
33
|
-
this.#Component = lazy(() => import('./devtools/
|
|
33
|
+
this.#Component = lazy(() => import('./devtools/UUNAZSBD.js'));
|
|
34
34
|
const Devtools = this.#Component;
|
|
35
35
|
this.#eventBus = new ClientEventBus(this.#eventBusConfig);
|
|
36
36
|
this.#eventBus.start();
|
|
@@ -1597,6 +1597,75 @@ var stylesFactory = (theme) => {
|
|
|
1597
1597
|
text-transform: uppercase;
|
|
1598
1598
|
letter-spacing: 0.05em;
|
|
1599
1599
|
`,
|
|
1600
|
+
pluginMarketplaceFeatureBanner: css2`
|
|
1601
|
+
margin-top: 1rem;
|
|
1602
|
+
padding: 1.25rem 1.5rem;
|
|
1603
|
+
background: ${t(
|
|
1604
|
+
"linear-gradient(135deg, #3b82f6 0%, #2563eb 100%)",
|
|
1605
|
+
"linear-gradient(135deg, #1e3a8a 0%, #1e40af 100%)"
|
|
1606
|
+
)};
|
|
1607
|
+
border-radius: 0.75rem;
|
|
1608
|
+
border: 1px solid ${t(colors.blue[400], colors.blue[800])};
|
|
1609
|
+
box-shadow:
|
|
1610
|
+
0 4px 6px -1px rgba(0, 0, 0, 0.1),
|
|
1611
|
+
0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
|
1612
|
+
`,
|
|
1613
|
+
pluginMarketplaceFeatureBannerContent: css2`
|
|
1614
|
+
display: flex;
|
|
1615
|
+
flex-direction: column;
|
|
1616
|
+
gap: 0.75rem;
|
|
1617
|
+
`,
|
|
1618
|
+
pluginMarketplaceFeatureBannerTitle: css2`
|
|
1619
|
+
font-size: 1.125rem;
|
|
1620
|
+
font-weight: 700;
|
|
1621
|
+
color: white;
|
|
1622
|
+
margin: 0;
|
|
1623
|
+
display: flex;
|
|
1624
|
+
align-items: center;
|
|
1625
|
+
gap: 0.5rem;
|
|
1626
|
+
`,
|
|
1627
|
+
pluginMarketplaceFeatureBannerIcon: css2`
|
|
1628
|
+
width: 24px;
|
|
1629
|
+
height: 24px;
|
|
1630
|
+
display: inline-flex;
|
|
1631
|
+
`,
|
|
1632
|
+
pluginMarketplaceFeatureBannerText: css2`
|
|
1633
|
+
font-size: 0.95rem;
|
|
1634
|
+
color: ${t("rgba(255, 255, 255, 0.95)", "rgba(255, 255, 255, 0.9)")};
|
|
1635
|
+
line-height: 1.5;
|
|
1636
|
+
margin: 0;
|
|
1637
|
+
`,
|
|
1638
|
+
pluginMarketplaceFeatureBannerButton: css2`
|
|
1639
|
+
display: inline-flex;
|
|
1640
|
+
align-items: center;
|
|
1641
|
+
gap: 0.5rem;
|
|
1642
|
+
padding: 0.625rem 1.25rem;
|
|
1643
|
+
background: white;
|
|
1644
|
+
color: ${colors.blue[600]};
|
|
1645
|
+
font-weight: 600;
|
|
1646
|
+
font-size: 0.95rem;
|
|
1647
|
+
border-radius: 0.5rem;
|
|
1648
|
+
border: none;
|
|
1649
|
+
cursor: pointer;
|
|
1650
|
+
transition: all 0.2s ease;
|
|
1651
|
+
text-decoration: none;
|
|
1652
|
+
align-self: flex-start;
|
|
1653
|
+
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
|
1654
|
+
|
|
1655
|
+
&:hover {
|
|
1656
|
+
background: ${t(colors.gray[50], colors.gray[100])};
|
|
1657
|
+
transform: translateY(-1px);
|
|
1658
|
+
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
|
|
1659
|
+
}
|
|
1660
|
+
|
|
1661
|
+
&:active {
|
|
1662
|
+
transform: translateY(0);
|
|
1663
|
+
}
|
|
1664
|
+
`,
|
|
1665
|
+
pluginMarketplaceFeatureBannerButtonIcon: css2`
|
|
1666
|
+
width: 18px;
|
|
1667
|
+
height: 18px;
|
|
1668
|
+
`,
|
|
1600
1669
|
pluginMarketplaceCardDisabled: css2`
|
|
1601
1670
|
opacity: 0.6;
|
|
1602
1671
|
filter: grayscale(0.3);
|
|
@@ -2249,16 +2318,28 @@ var PluginCardComponent = (props) => {
|
|
|
2249
2318
|
};
|
|
2250
2319
|
|
|
2251
2320
|
// src/tabs/marketplace/plugin-section.tsx
|
|
2252
|
-
var _tmpl$12 =
|
|
2253
|
-
var _tmpl$25 =
|
|
2321
|
+
var _tmpl$12 = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"></path></svg>';
|
|
2322
|
+
var _tmpl$25 = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="4" width="20" height="16" rx="2"></rect><path d="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7"></path></svg>';
|
|
2323
|
+
var _tmpl$34 = ["<div", "><div", "><h4", "><span", ">", "</span>Want to be featured here?</h4><p", `>If you've built a plugin for TanStack Devtools and would like to showcase it in the featured section, we'd love to hear from you! Reach out to us to discuss partnership opportunities.</p><a href="mailto:partners+devtools@tanstack.com?subject=Featured%20Plugin%20Partnership%20Inquiry"`, "><span", ">", "</span>Contact Us</a></div></div>"];
|
|
2324
|
+
var _tmpl$44 = ["<div", ">", "</div>"];
|
|
2325
|
+
var _tmpl$53 = ["<div", "><div", "><div", '><div class="', '">', "</div><h3", ">", "</h3></div></div>", "</div>"];
|
|
2326
|
+
var StarIcon = () => ssr(_tmpl$12);
|
|
2327
|
+
var MailIcon = () => ssr(_tmpl$25);
|
|
2254
2328
|
var PluginSectionComponent = (props) => {
|
|
2255
2329
|
const styles = useStyles();
|
|
2256
|
-
return ssr(_tmpl$
|
|
2330
|
+
return ssr(_tmpl$53, ssrAttribute("class", escape(styles().pluginMarketplaceSection, true), false), ssrAttribute("class", escape(styles().pluginMarketplaceSectionHeader, true), false), ssrAttribute("class", escape(styles().pluginMarketplaceSectionHeaderLeft, true), false), `${escape(styles().pluginMarketplaceSectionChevron, true) || ""} ${props.isCollapsed() ? escape(escape(styles().pluginMarketplaceSectionChevronCollapsed, true), true) : ""}`, escape(createComponent(ChevronDownIcon, {})), ssrAttribute("class", escape(styles().pluginMarketplaceSectionTitle, true), false), escape(props.section.displayName), escape(createComponent(Show, {
|
|
2257
2331
|
get when() {
|
|
2258
2332
|
return !props.isCollapsed();
|
|
2259
2333
|
},
|
|
2260
2334
|
get children() {
|
|
2261
|
-
return
|
|
2335
|
+
return [createComponent(Show, {
|
|
2336
|
+
get when() {
|
|
2337
|
+
return props.section.id === "featured";
|
|
2338
|
+
},
|
|
2339
|
+
get children() {
|
|
2340
|
+
return ssr(_tmpl$34, ssrAttribute("class", escape(styles().pluginMarketplaceFeatureBanner, true), false), ssrAttribute("class", escape(styles().pluginMarketplaceFeatureBannerContent, true), false), ssrAttribute("class", escape(styles().pluginMarketplaceFeatureBannerTitle, true), false), ssrAttribute("class", escape(styles().pluginMarketplaceFeatureBannerIcon, true), false), escape(createComponent(StarIcon, {})), ssrAttribute("class", escape(styles().pluginMarketplaceFeatureBannerText, true), false), ssrAttribute("class", escape(styles().pluginMarketplaceFeatureBannerButton, true), false), ssrAttribute("class", escape(styles().pluginMarketplaceFeatureBannerButtonIcon, true), false), escape(createComponent(MailIcon, {})));
|
|
2341
|
+
}
|
|
2342
|
+
}), ssr(_tmpl$44, ssrAttribute("class", escape(styles().pluginMarketplaceGrid, true), false), escape(createComponent(For, {
|
|
2262
2343
|
get each() {
|
|
2263
2344
|
return props.section.cards;
|
|
2264
2345
|
},
|
|
@@ -2268,7 +2349,7 @@ var PluginSectionComponent = (props) => {
|
|
|
2268
2349
|
return props.onCardAction;
|
|
2269
2350
|
}
|
|
2270
2351
|
})
|
|
2271
|
-
})));
|
|
2352
|
+
})))];
|
|
2272
2353
|
}
|
|
2273
2354
|
})));
|
|
2274
2355
|
};
|
|
@@ -2467,11 +2548,36 @@ var PLUGIN_REGISTRY = {
|
|
|
2467
2548
|
isNew: true,
|
|
2468
2549
|
// New plugin banner
|
|
2469
2550
|
tags: ["TanStack"]
|
|
2470
|
-
}
|
|
2551
|
+
},
|
|
2471
2552
|
// ==========================================
|
|
2472
2553
|
// THIRD-PARTY PLUGINS - Examples
|
|
2473
2554
|
// ==========================================
|
|
2474
2555
|
// External contributors can add their plugins below!
|
|
2556
|
+
// Dimano — Prefetch Heatmap for TanStack Router
|
|
2557
|
+
"@dimano/ts-devtools-plugin-prefetch-heatmap": {
|
|
2558
|
+
packageName: "@dimano/ts-devtools-plugin-prefetch-heatmap",
|
|
2559
|
+
title: "Prefetch Heatmap",
|
|
2560
|
+
description: "Visualize TanStack Router prefetch intent, hits, and waste with a color overlay and a live metrics panel.",
|
|
2561
|
+
requires: {
|
|
2562
|
+
packageName: "@tanstack/react-router",
|
|
2563
|
+
minVersion: "1.0.0"
|
|
2564
|
+
},
|
|
2565
|
+
// default export registers the plugin
|
|
2566
|
+
pluginImport: {
|
|
2567
|
+
importName: "registerPrefetchHeatmapPlugin",
|
|
2568
|
+
type: "function"
|
|
2569
|
+
},
|
|
2570
|
+
// helps the host match your plugin deterministically
|
|
2571
|
+
pluginId: "prefetch-heatmap",
|
|
2572
|
+
// show a nice card in the marketplace
|
|
2573
|
+
logoUrl: "https://raw.githubusercontent.com/dimitrianoudi/tanstack-prefetch-heatmap/main/assets/prefetch-heatmap-card.png",
|
|
2574
|
+
docsUrl: "https://github.com/dimitrianoudi/tanstack-prefetch-heatmap#prefetch-heatmap-devtools-plugin",
|
|
2575
|
+
repoUrl: "https://github.com/dimitrianoudi/tanstack-prefetch-heatmap",
|
|
2576
|
+
author: "Dimitris Anoudis (@dimitrianoudi)",
|
|
2577
|
+
framework: "react",
|
|
2578
|
+
isNew: true,
|
|
2579
|
+
tags: ["Router", "Prefetch", "Analytics", "Overlay", "TanStack"]
|
|
2580
|
+
}
|
|
2475
2581
|
};
|
|
2476
2582
|
function getAllPluginMetadata() {
|
|
2477
2583
|
return Object.values(PLUGIN_REGISTRY);
|
|
@@ -2657,6 +2763,15 @@ var buildPluginCards = (pkg, currentFramework, registeredPlugins, existingCards)
|
|
|
2657
2763
|
};
|
|
2658
2764
|
var groupIntoSections = (allCards) => {
|
|
2659
2765
|
const sections = [];
|
|
2766
|
+
const featuredCards = allCards.filter(
|
|
2767
|
+
(c) => c.metadata?.featured && c.actionType !== "already-installed" && c.isCurrentFramework
|
|
2768
|
+
// Only show featured plugins for current framework
|
|
2769
|
+
);
|
|
2770
|
+
sections.push({
|
|
2771
|
+
id: "featured",
|
|
2772
|
+
displayName: "\u2B50 Featured",
|
|
2773
|
+
cards: featuredCards
|
|
2774
|
+
});
|
|
2660
2775
|
const activeCards = allCards.filter(
|
|
2661
2776
|
(c) => c.actionType === "already-installed" && c.isRegistered
|
|
2662
2777
|
);
|
|
@@ -2667,17 +2782,6 @@ var groupIntoSections = (allCards) => {
|
|
|
2667
2782
|
cards: activeCards
|
|
2668
2783
|
});
|
|
2669
2784
|
}
|
|
2670
|
-
const featuredCards = allCards.filter(
|
|
2671
|
-
(c) => c.metadata?.featured && c.actionType !== "already-installed" && c.isCurrentFramework
|
|
2672
|
-
// Only show featured plugins for current framework
|
|
2673
|
-
);
|
|
2674
|
-
if (featuredCards.length > 0) {
|
|
2675
|
-
sections.push({
|
|
2676
|
-
id: "featured",
|
|
2677
|
-
displayName: "\u2B50 Featured",
|
|
2678
|
-
cards: featuredCards
|
|
2679
|
-
});
|
|
2680
|
-
}
|
|
2681
2785
|
const availableCards = allCards.filter(
|
|
2682
2786
|
(c) => c.isCurrentFramework && c.actionType !== "already-installed" && !c.metadata?.featured
|
|
2683
2787
|
// Not featured (already in featured section)
|
|
@@ -2922,7 +3026,7 @@ var PluginMarketplace = () => {
|
|
|
2922
3026
|
// src/tabs/plugins-tab.tsx
|
|
2923
3027
|
var _tmpl$17 = ["<div", "><div", "><div", "><div", ">", "</div><div", "><h3>Add More</h3></div></div></div>", "</div>"];
|
|
2924
3028
|
var _tmpl$28 = ["<div", '><h3 id="', '"></h3></div>'];
|
|
2925
|
-
var _tmpl$
|
|
3029
|
+
var _tmpl$35 = ['<div id="', '"', "></div>"];
|
|
2926
3030
|
var PluginsTab = () => {
|
|
2927
3031
|
const {
|
|
2928
3032
|
plugins,
|
|
@@ -2987,7 +3091,7 @@ var PluginsTab = () => {
|
|
|
2987
3091
|
get each() {
|
|
2988
3092
|
return activePlugins();
|
|
2989
3093
|
},
|
|
2990
|
-
children: (pluginId) => ssr(_tmpl$
|
|
3094
|
+
children: (pluginId) => ssr(_tmpl$35, `${escape(PLUGIN_CONTAINER_ID, true)}-${escape(pluginId, true)}`, ssrAttribute("class", escape(styles().pluginsTabContent, true), false))
|
|
2991
3095
|
});
|
|
2992
3096
|
},
|
|
2993
3097
|
get children() {
|
|
@@ -3061,9 +3165,9 @@ function useHeadChanges(onChange, opts = {}) {
|
|
|
3061
3165
|
// src/tabs/seo-tab.tsx
|
|
3062
3166
|
var _tmpl$18 = ["<div", ' style="', '"><div', ' style="', '">', " Preview</div>", "<div", ">", "</div><div", ">", "</div><div", ">", "</div></div>"];
|
|
3063
3167
|
var _tmpl$29 = ["<img", ' alt="Preview"', ">"];
|
|
3064
|
-
var _tmpl$
|
|
3065
|
-
var _tmpl$
|
|
3066
|
-
var _tmpl$
|
|
3168
|
+
var _tmpl$36 = ["<div", ' style="', '">No Image</div>'];
|
|
3169
|
+
var _tmpl$45 = ["<div", ">", "</div>"];
|
|
3170
|
+
var _tmpl$54 = ["<div>", "", "</div>"];
|
|
3067
3171
|
var _tmpl$63 = ["<div", "><strong>Missing tags for ", ":</strong><ul", ">", "</ul></div>"];
|
|
3068
3172
|
var _tmpl$72 = ["<li", ">", "</li>"];
|
|
3069
3173
|
var SOCIALS = [
|
|
@@ -3190,7 +3294,7 @@ var SOCIALS = [
|
|
|
3190
3294
|
];
|
|
3191
3295
|
function SocialPreview(props) {
|
|
3192
3296
|
const styles = useStyles();
|
|
3193
|
-
return ssr(_tmpl$18, ssrAttribute("class", escape(styles().seoPreviewCard, true), false), "border-color:" + escape(props.color, true), ssrAttribute("class", escape(styles().seoPreviewHeader, true), false), "color:" + escape(props.color, true), escape(props.network), props.meta.image ? ssr(_tmpl$29, ssrAttribute("src", escape(props.meta.image, true), false), ssrAttribute("class", escape(styles().seoPreviewImage, true), false)) : ssr(_tmpl$
|
|
3297
|
+
return ssr(_tmpl$18, ssrAttribute("class", escape(styles().seoPreviewCard, true), false), "border-color:" + escape(props.color, true), ssrAttribute("class", escape(styles().seoPreviewHeader, true), false), "color:" + escape(props.color, true), escape(props.network), props.meta.image ? ssr(_tmpl$29, ssrAttribute("src", escape(props.meta.image, true), false), ssrAttribute("class", escape(styles().seoPreviewImage, true), false)) : ssr(_tmpl$36, ssrAttribute("class", escape(styles().seoPreviewImage, true), false), "background:#222;color:#888;display:flex;align-items:center;justify-content:center;min-height:80px;width:100%"), ssrAttribute("class", escape(styles().seoPreviewTitle, true), false), escape(props.meta.title) || "No Title", ssrAttribute("class", escape(styles().seoPreviewDesc, true), false), escape(props.meta.description) || "No Description", ssrAttribute("class", escape(styles().seoPreviewUrl, true), false), escape(props.meta.url) || escape(window.location.href));
|
|
3194
3298
|
}
|
|
3195
3299
|
var SeoTab = () => {
|
|
3196
3300
|
const [reports, setReports] = createSignal(analyzeHead());
|
|
@@ -3235,13 +3339,13 @@ var SeoTab = () => {
|
|
|
3235
3339
|
}
|
|
3236
3340
|
}), createComponent(SectionDescription, {
|
|
3237
3341
|
children: "See how your current page will look when shared on popular social networks. The tool checks for essential meta tags and highlights any that are missing."
|
|
3238
|
-
}), ssr(_tmpl$
|
|
3342
|
+
}), ssr(_tmpl$45, ssrAttribute("class", escape(styles().seoPreviewSection, true), false), escape(createComponent(For, {
|
|
3239
3343
|
get each() {
|
|
3240
3344
|
return reports();
|
|
3241
3345
|
},
|
|
3242
3346
|
children: (report, i) => {
|
|
3243
3347
|
const social = SOCIALS[i()];
|
|
3244
|
-
return ssr(_tmpl$
|
|
3348
|
+
return ssr(_tmpl$54, escape(createComponent(SocialPreview, {
|
|
3245
3349
|
get meta() {
|
|
3246
3350
|
return report.found;
|
|
3247
3351
|
},
|
|
@@ -3286,7 +3390,7 @@ var tabs = [{
|
|
|
3286
3390
|
// src/components/tabs.tsx
|
|
3287
3391
|
var _tmpl$19 = ["<div", ">", "", "</div>"];
|
|
3288
3392
|
var _tmpl$210 = ['<button type="button"', ">", "</button>"];
|
|
3289
|
-
var _tmpl$
|
|
3393
|
+
var _tmpl$37 = ['<div style="', '"><button type="button"', ">", '</button><button type="button"', ">", "</button></div>"];
|
|
3290
3394
|
var Tabs = (props) => {
|
|
3291
3395
|
const styles = useStyles();
|
|
3292
3396
|
const {
|
|
@@ -3302,7 +3406,7 @@ var Tabs = (props) => {
|
|
|
3302
3406
|
children: (tab) => ssr(_tmpl$210, ssrAttribute("class", escape(clsx3(styles().tab, {
|
|
3303
3407
|
active: state().activeTab === tab.id
|
|
3304
3408
|
}), true), false), escape(tab.icon()))
|
|
3305
|
-
})), pipWindow().pipWindow !== null ? escape(null) : ssr(_tmpl$
|
|
3409
|
+
})), pipWindow().pipWindow !== null ? escape(null) : ssr(_tmpl$37, "margin-top:auto", ssrAttribute("class", escape(clsx3(styles().tab, "detach"), true), false), escape(createComponent(PiP, {})), ssrAttribute("class", escape(clsx3(styles().tab, "close"), true), false), escape(createComponent(X, {}))));
|
|
3306
3410
|
};
|
|
3307
3411
|
var _tmpl$20 = ["<div", ">", "</div>"];
|
|
3308
3412
|
var TabContent = () => {
|
|
@@ -1597,6 +1597,75 @@ var stylesFactory = (theme) => {
|
|
|
1597
1597
|
text-transform: uppercase;
|
|
1598
1598
|
letter-spacing: 0.05em;
|
|
1599
1599
|
`,
|
|
1600
|
+
pluginMarketplaceFeatureBanner: css2`
|
|
1601
|
+
margin-top: 1rem;
|
|
1602
|
+
padding: 1.25rem 1.5rem;
|
|
1603
|
+
background: ${t(
|
|
1604
|
+
"linear-gradient(135deg, #3b82f6 0%, #2563eb 100%)",
|
|
1605
|
+
"linear-gradient(135deg, #1e3a8a 0%, #1e40af 100%)"
|
|
1606
|
+
)};
|
|
1607
|
+
border-radius: 0.75rem;
|
|
1608
|
+
border: 1px solid ${t(colors.blue[400], colors.blue[800])};
|
|
1609
|
+
box-shadow:
|
|
1610
|
+
0 4px 6px -1px rgba(0, 0, 0, 0.1),
|
|
1611
|
+
0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
|
1612
|
+
`,
|
|
1613
|
+
pluginMarketplaceFeatureBannerContent: css2`
|
|
1614
|
+
display: flex;
|
|
1615
|
+
flex-direction: column;
|
|
1616
|
+
gap: 0.75rem;
|
|
1617
|
+
`,
|
|
1618
|
+
pluginMarketplaceFeatureBannerTitle: css2`
|
|
1619
|
+
font-size: 1.125rem;
|
|
1620
|
+
font-weight: 700;
|
|
1621
|
+
color: white;
|
|
1622
|
+
margin: 0;
|
|
1623
|
+
display: flex;
|
|
1624
|
+
align-items: center;
|
|
1625
|
+
gap: 0.5rem;
|
|
1626
|
+
`,
|
|
1627
|
+
pluginMarketplaceFeatureBannerIcon: css2`
|
|
1628
|
+
width: 24px;
|
|
1629
|
+
height: 24px;
|
|
1630
|
+
display: inline-flex;
|
|
1631
|
+
`,
|
|
1632
|
+
pluginMarketplaceFeatureBannerText: css2`
|
|
1633
|
+
font-size: 0.95rem;
|
|
1634
|
+
color: ${t("rgba(255, 255, 255, 0.95)", "rgba(255, 255, 255, 0.9)")};
|
|
1635
|
+
line-height: 1.5;
|
|
1636
|
+
margin: 0;
|
|
1637
|
+
`,
|
|
1638
|
+
pluginMarketplaceFeatureBannerButton: css2`
|
|
1639
|
+
display: inline-flex;
|
|
1640
|
+
align-items: center;
|
|
1641
|
+
gap: 0.5rem;
|
|
1642
|
+
padding: 0.625rem 1.25rem;
|
|
1643
|
+
background: white;
|
|
1644
|
+
color: ${colors.blue[600]};
|
|
1645
|
+
font-weight: 600;
|
|
1646
|
+
font-size: 0.95rem;
|
|
1647
|
+
border-radius: 0.5rem;
|
|
1648
|
+
border: none;
|
|
1649
|
+
cursor: pointer;
|
|
1650
|
+
transition: all 0.2s ease;
|
|
1651
|
+
text-decoration: none;
|
|
1652
|
+
align-self: flex-start;
|
|
1653
|
+
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
|
1654
|
+
|
|
1655
|
+
&:hover {
|
|
1656
|
+
background: ${t(colors.gray[50], colors.gray[100])};
|
|
1657
|
+
transform: translateY(-1px);
|
|
1658
|
+
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
|
|
1659
|
+
}
|
|
1660
|
+
|
|
1661
|
+
&:active {
|
|
1662
|
+
transform: translateY(0);
|
|
1663
|
+
}
|
|
1664
|
+
`,
|
|
1665
|
+
pluginMarketplaceFeatureBannerButtonIcon: css2`
|
|
1666
|
+
width: 18px;
|
|
1667
|
+
height: 18px;
|
|
1668
|
+
`,
|
|
1600
1669
|
pluginMarketplaceCardDisabled: css2`
|
|
1601
1670
|
opacity: 0.6;
|
|
1602
1671
|
filter: grayscale(0.3);
|
|
@@ -2438,46 +2507,82 @@ var PluginCardComponent = (props) => {
|
|
|
2438
2507
|
};
|
|
2439
2508
|
|
|
2440
2509
|
// src/tabs/marketplace/plugin-section.tsx
|
|
2441
|
-
var _tmpl$10 = /* @__PURE__ */ template(`<
|
|
2442
|
-
var _tmpl$24 = /* @__PURE__ */ template(`<
|
|
2510
|
+
var _tmpl$10 = /* @__PURE__ */ template(`<svg xmlns=http://www.w3.org/2000/svg viewBox="0 0 24 24"fill=currentColor><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z">`);
|
|
2511
|
+
var _tmpl$24 = /* @__PURE__ */ template(`<svg xmlns=http://www.w3.org/2000/svg viewBox="0 0 24 24"fill=none stroke=currentColor stroke-width=2 stroke-linecap=round stroke-linejoin=round><rect x=2 y=4 width=20 height=16 rx=2></rect><path d="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7">`);
|
|
2512
|
+
var _tmpl$34 = /* @__PURE__ */ template(`<div><div><h4><span></span>Want to be featured here?</h4><p>If you've built a plugin for TanStack Devtools and would like to showcase it in the featured section, we'd love to hear from you! Reach out to us to discuss partnership opportunities.</p><a href="mailto:partners+devtools@tanstack.com?subject=Featured%20Plugin%20Partnership%20Inquiry"><span></span>Contact Us`);
|
|
2513
|
+
var _tmpl$43 = /* @__PURE__ */ template(`<div>`);
|
|
2514
|
+
var _tmpl$53 = /* @__PURE__ */ template(`<div><div><div><div></div><h3>`);
|
|
2515
|
+
var StarIcon = () => _tmpl$10();
|
|
2516
|
+
var MailIcon = () => _tmpl$24();
|
|
2443
2517
|
var PluginSectionComponent = (props) => {
|
|
2444
2518
|
const styles = useStyles();
|
|
2445
2519
|
return (() => {
|
|
2446
|
-
var _el$ = _tmpl$
|
|
2447
|
-
addEventListener(_el$
|
|
2448
|
-
insert(_el$
|
|
2449
|
-
insert(_el$
|
|
2450
|
-
insert(_el
|
|
2520
|
+
var _el$3 = _tmpl$53(), _el$4 = _el$3.firstChild, _el$5 = _el$4.firstChild, _el$6 = _el$5.firstChild, _el$7 = _el$6.nextSibling;
|
|
2521
|
+
addEventListener(_el$4, "click", props.onToggleCollapse, true);
|
|
2522
|
+
insert(_el$6, createComponent(ChevronDownIcon, {}));
|
|
2523
|
+
insert(_el$7, () => props.section.displayName);
|
|
2524
|
+
insert(_el$3, createComponent(Show, {
|
|
2451
2525
|
get when() {
|
|
2452
2526
|
return !props.isCollapsed();
|
|
2453
2527
|
},
|
|
2454
2528
|
get children() {
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
return props.section.cards;
|
|
2529
|
+
return [createComponent(Show, {
|
|
2530
|
+
get when() {
|
|
2531
|
+
return props.section.id === "featured";
|
|
2459
2532
|
},
|
|
2460
|
-
children
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2533
|
+
get children() {
|
|
2534
|
+
var _el$8 = _tmpl$34(), _el$9 = _el$8.firstChild, _el$0 = _el$9.firstChild, _el$1 = _el$0.firstChild, _el$10 = _el$0.nextSibling, _el$11 = _el$10.nextSibling, _el$12 = _el$11.firstChild;
|
|
2535
|
+
insert(_el$1, createComponent(StarIcon, {}));
|
|
2536
|
+
insert(_el$12, createComponent(MailIcon, {}));
|
|
2537
|
+
effect((_p$) => {
|
|
2538
|
+
var _v$ = styles().pluginMarketplaceFeatureBanner, _v$2 = styles().pluginMarketplaceFeatureBannerContent, _v$3 = styles().pluginMarketplaceFeatureBannerTitle, _v$4 = styles().pluginMarketplaceFeatureBannerIcon, _v$5 = styles().pluginMarketplaceFeatureBannerText, _v$6 = styles().pluginMarketplaceFeatureBannerButton, _v$7 = styles().pluginMarketplaceFeatureBannerButtonIcon;
|
|
2539
|
+
_v$ !== _p$.e && className(_el$8, _p$.e = _v$);
|
|
2540
|
+
_v$2 !== _p$.t && className(_el$9, _p$.t = _v$2);
|
|
2541
|
+
_v$3 !== _p$.a && className(_el$0, _p$.a = _v$3);
|
|
2542
|
+
_v$4 !== _p$.o && className(_el$1, _p$.o = _v$4);
|
|
2543
|
+
_v$5 !== _p$.i && className(_el$10, _p$.i = _v$5);
|
|
2544
|
+
_v$6 !== _p$.n && className(_el$11, _p$.n = _v$6);
|
|
2545
|
+
_v$7 !== _p$.s && className(_el$12, _p$.s = _v$7);
|
|
2546
|
+
return _p$;
|
|
2547
|
+
}, {
|
|
2548
|
+
e: void 0,
|
|
2549
|
+
t: void 0,
|
|
2550
|
+
a: void 0,
|
|
2551
|
+
o: void 0,
|
|
2552
|
+
i: void 0,
|
|
2553
|
+
n: void 0,
|
|
2554
|
+
s: void 0
|
|
2555
|
+
});
|
|
2556
|
+
return _el$8;
|
|
2557
|
+
}
|
|
2558
|
+
}), (() => {
|
|
2559
|
+
var _el$13 = _tmpl$43();
|
|
2560
|
+
insert(_el$13, createComponent(For, {
|
|
2561
|
+
get each() {
|
|
2562
|
+
return props.section.cards;
|
|
2563
|
+
},
|
|
2564
|
+
children: (card) => createComponent(PluginCardComponent, {
|
|
2565
|
+
card,
|
|
2566
|
+
get onAction() {
|
|
2567
|
+
return props.onCardAction;
|
|
2568
|
+
}
|
|
2569
|
+
})
|
|
2570
|
+
}));
|
|
2571
|
+
effect(() => className(_el$13, styles().pluginMarketplaceGrid));
|
|
2572
|
+
return _el$13;
|
|
2573
|
+
})()];
|
|
2469
2574
|
}
|
|
2470
2575
|
}), null);
|
|
2471
2576
|
effect((_p$) => {
|
|
2472
|
-
var _v$ = styles().pluginMarketplaceSection, _v$
|
|
2577
|
+
var _v$8 = styles().pluginMarketplaceSection, _v$9 = styles().pluginMarketplaceSectionHeader, _v$0 = styles().pluginMarketplaceSectionHeaderLeft, _v$1 = styles().pluginMarketplaceSectionChevron, _v$10 = {
|
|
2473
2578
|
[styles().pluginMarketplaceSectionChevronCollapsed]: props.isCollapsed()
|
|
2474
|
-
}, _v$
|
|
2475
|
-
_v$ !== _p$.e && className(_el
|
|
2476
|
-
_v$
|
|
2477
|
-
_v$
|
|
2478
|
-
_v$
|
|
2479
|
-
_p$.i = classList(_el$
|
|
2480
|
-
_v$
|
|
2579
|
+
}, _v$11 = styles().pluginMarketplaceSectionTitle;
|
|
2580
|
+
_v$8 !== _p$.e && className(_el$3, _p$.e = _v$8);
|
|
2581
|
+
_v$9 !== _p$.t && className(_el$4, _p$.t = _v$9);
|
|
2582
|
+
_v$0 !== _p$.a && className(_el$5, _p$.a = _v$0);
|
|
2583
|
+
_v$1 !== _p$.o && className(_el$6, _p$.o = _v$1);
|
|
2584
|
+
_p$.i = classList(_el$6, _v$10, _p$.i);
|
|
2585
|
+
_v$11 !== _p$.n && className(_el$7, _p$.n = _v$11);
|
|
2481
2586
|
return _p$;
|
|
2482
2587
|
}, {
|
|
2483
2588
|
e: void 0,
|
|
@@ -2487,7 +2592,7 @@ var PluginSectionComponent = (props) => {
|
|
|
2487
2592
|
i: void 0,
|
|
2488
2593
|
n: void 0
|
|
2489
2594
|
});
|
|
2490
|
-
return _el
|
|
2595
|
+
return _el$3;
|
|
2491
2596
|
})();
|
|
2492
2597
|
};
|
|
2493
2598
|
delegateEvents(["click"]);
|
|
@@ -2757,11 +2862,36 @@ var PLUGIN_REGISTRY = {
|
|
|
2757
2862
|
isNew: true,
|
|
2758
2863
|
// New plugin banner
|
|
2759
2864
|
tags: ["TanStack"]
|
|
2760
|
-
}
|
|
2865
|
+
},
|
|
2761
2866
|
// ==========================================
|
|
2762
2867
|
// THIRD-PARTY PLUGINS - Examples
|
|
2763
2868
|
// ==========================================
|
|
2764
2869
|
// External contributors can add their plugins below!
|
|
2870
|
+
// Dimano — Prefetch Heatmap for TanStack Router
|
|
2871
|
+
"@dimano/ts-devtools-plugin-prefetch-heatmap": {
|
|
2872
|
+
packageName: "@dimano/ts-devtools-plugin-prefetch-heatmap",
|
|
2873
|
+
title: "Prefetch Heatmap",
|
|
2874
|
+
description: "Visualize TanStack Router prefetch intent, hits, and waste with a color overlay and a live metrics panel.",
|
|
2875
|
+
requires: {
|
|
2876
|
+
packageName: "@tanstack/react-router",
|
|
2877
|
+
minVersion: "1.0.0"
|
|
2878
|
+
},
|
|
2879
|
+
// default export registers the plugin
|
|
2880
|
+
pluginImport: {
|
|
2881
|
+
importName: "registerPrefetchHeatmapPlugin",
|
|
2882
|
+
type: "function"
|
|
2883
|
+
},
|
|
2884
|
+
// helps the host match your plugin deterministically
|
|
2885
|
+
pluginId: "prefetch-heatmap",
|
|
2886
|
+
// show a nice card in the marketplace
|
|
2887
|
+
logoUrl: "https://raw.githubusercontent.com/dimitrianoudi/tanstack-prefetch-heatmap/main/assets/prefetch-heatmap-card.png",
|
|
2888
|
+
docsUrl: "https://github.com/dimitrianoudi/tanstack-prefetch-heatmap#prefetch-heatmap-devtools-plugin",
|
|
2889
|
+
repoUrl: "https://github.com/dimitrianoudi/tanstack-prefetch-heatmap",
|
|
2890
|
+
author: "Dimitris Anoudis (@dimitrianoudi)",
|
|
2891
|
+
framework: "react",
|
|
2892
|
+
isNew: true,
|
|
2893
|
+
tags: ["Router", "Prefetch", "Analytics", "Overlay", "TanStack"]
|
|
2894
|
+
}
|
|
2765
2895
|
};
|
|
2766
2896
|
function getAllPluginMetadata() {
|
|
2767
2897
|
return Object.values(PLUGIN_REGISTRY);
|
|
@@ -2947,6 +3077,15 @@ var buildPluginCards = (pkg, currentFramework, registeredPlugins, existingCards)
|
|
|
2947
3077
|
};
|
|
2948
3078
|
var groupIntoSections = (allCards) => {
|
|
2949
3079
|
const sections = [];
|
|
3080
|
+
const featuredCards = allCards.filter(
|
|
3081
|
+
(c) => c.metadata?.featured && c.actionType !== "already-installed" && c.isCurrentFramework
|
|
3082
|
+
// Only show featured plugins for current framework
|
|
3083
|
+
);
|
|
3084
|
+
sections.push({
|
|
3085
|
+
id: "featured",
|
|
3086
|
+
displayName: "\u2B50 Featured",
|
|
3087
|
+
cards: featuredCards
|
|
3088
|
+
});
|
|
2950
3089
|
const activeCards = allCards.filter(
|
|
2951
3090
|
(c) => c.actionType === "already-installed" && c.isRegistered
|
|
2952
3091
|
);
|
|
@@ -2957,17 +3096,6 @@ var groupIntoSections = (allCards) => {
|
|
|
2957
3096
|
cards: activeCards
|
|
2958
3097
|
});
|
|
2959
3098
|
}
|
|
2960
|
-
const featuredCards = allCards.filter(
|
|
2961
|
-
(c) => c.metadata?.featured && c.actionType !== "already-installed" && c.isCurrentFramework
|
|
2962
|
-
// Only show featured plugins for current framework
|
|
2963
|
-
);
|
|
2964
|
-
if (featuredCards.length > 0) {
|
|
2965
|
-
sections.push({
|
|
2966
|
-
id: "featured",
|
|
2967
|
-
displayName: "\u2B50 Featured",
|
|
2968
|
-
cards: featuredCards
|
|
2969
|
-
});
|
|
2970
|
-
}
|
|
2971
3099
|
const availableCards = allCards.filter(
|
|
2972
3100
|
(c) => c.isCurrentFramework && c.actionType !== "already-installed" && !c.metadata?.featured
|
|
2973
3101
|
// Not featured (already in featured section)
|
|
@@ -3234,7 +3362,7 @@ var PluginMarketplace = () => {
|
|
|
3234
3362
|
// src/tabs/plugins-tab.tsx
|
|
3235
3363
|
var _tmpl$15 = /* @__PURE__ */ template(`<div><div><div><div></div><div><h3>Add More`);
|
|
3236
3364
|
var _tmpl$27 = /* @__PURE__ */ template(`<div><h3>`);
|
|
3237
|
-
var _tmpl$
|
|
3365
|
+
var _tmpl$35 = /* @__PURE__ */ template(`<div>`);
|
|
3238
3366
|
var PluginsTab = () => {
|
|
3239
3367
|
const {
|
|
3240
3368
|
plugins,
|
|
@@ -3331,7 +3459,7 @@ var PluginsTab = () => {
|
|
|
3331
3459
|
return activePlugins();
|
|
3332
3460
|
},
|
|
3333
3461
|
children: (pluginId) => (() => {
|
|
3334
|
-
var _el$8 = _tmpl$
|
|
3462
|
+
var _el$8 = _tmpl$35();
|
|
3335
3463
|
use((el) => {
|
|
3336
3464
|
setPluginRefs((prev) => {
|
|
3337
3465
|
const updated = new Map(prev);
|
|
@@ -3437,9 +3565,9 @@ function useHeadChanges(onChange, opts = {}) {
|
|
|
3437
3565
|
// src/tabs/seo-tab.tsx
|
|
3438
3566
|
var _tmpl$16 = /* @__PURE__ */ template(`<div><div> Preview</div><div></div><div></div><div>`);
|
|
3439
3567
|
var _tmpl$28 = /* @__PURE__ */ template(`<img alt=Preview>`);
|
|
3440
|
-
var _tmpl$
|
|
3441
|
-
var _tmpl$
|
|
3442
|
-
var _tmpl$
|
|
3568
|
+
var _tmpl$36 = /* @__PURE__ */ template(`<div>No Image`);
|
|
3569
|
+
var _tmpl$44 = /* @__PURE__ */ template(`<div>`);
|
|
3570
|
+
var _tmpl$54 = /* @__PURE__ */ template(`<div><strong>Missing tags for <!>:</strong><ul>`);
|
|
3443
3571
|
var _tmpl$62 = /* @__PURE__ */ template(`<li>`);
|
|
3444
3572
|
var SOCIALS = [
|
|
3445
3573
|
{
|
|
@@ -3583,7 +3711,7 @@ function SocialPreview(props) {
|
|
|
3583
3711
|
});
|
|
3584
3712
|
return _el$7;
|
|
3585
3713
|
})() : (() => {
|
|
3586
|
-
var _el$8 = _tmpl$
|
|
3714
|
+
var _el$8 = _tmpl$36();
|
|
3587
3715
|
_el$8.style.setProperty("background", "#222");
|
|
3588
3716
|
_el$8.style.setProperty("color", "#888");
|
|
3589
3717
|
_el$8.style.setProperty("display", "flex");
|
|
@@ -3664,7 +3792,7 @@ var SeoTab = () => {
|
|
|
3664
3792
|
}), createComponent(SectionDescription, {
|
|
3665
3793
|
children: "See how your current page will look when shared on popular social networks. The tool checks for essential meta tags and highlights any that are missing."
|
|
3666
3794
|
}), (() => {
|
|
3667
|
-
var _el$9 = _tmpl$
|
|
3795
|
+
var _el$9 = _tmpl$44();
|
|
3668
3796
|
insert(_el$9, createComponent(For, {
|
|
3669
3797
|
get each() {
|
|
3670
3798
|
return reports();
|
|
@@ -3672,7 +3800,7 @@ var SeoTab = () => {
|
|
|
3672
3800
|
children: (report, i) => {
|
|
3673
3801
|
const social = SOCIALS[i()];
|
|
3674
3802
|
return (() => {
|
|
3675
|
-
var _el$0 = _tmpl$
|
|
3803
|
+
var _el$0 = _tmpl$44();
|
|
3676
3804
|
insert(_el$0, createComponent(SocialPreview, {
|
|
3677
3805
|
get meta() {
|
|
3678
3806
|
return report.found;
|
|
@@ -3687,7 +3815,7 @@ var SeoTab = () => {
|
|
|
3687
3815
|
insert(_el$0, (() => {
|
|
3688
3816
|
var _c$2 = memo(() => report.missing.length > 0);
|
|
3689
3817
|
return () => _c$2() ? (() => {
|
|
3690
|
-
var _el$1 = _tmpl$
|
|
3818
|
+
var _el$1 = _tmpl$54(), _el$10 = _el$1.firstChild, _el$11 = _el$10.firstChild, _el$13 = _el$11.nextSibling; _el$13.nextSibling; var _el$14 = _el$10.nextSibling;
|
|
3691
3819
|
insert(_el$10, () => social?.network, _el$13);
|
|
3692
3820
|
insert(_el$14, createComponent(For, {
|
|
3693
3821
|
get each() {
|
|
@@ -3746,7 +3874,7 @@ var tabs = [{
|
|
|
3746
3874
|
// src/components/tabs.tsx
|
|
3747
3875
|
var _tmpl$17 = /* @__PURE__ */ template(`<div>`);
|
|
3748
3876
|
var _tmpl$29 = /* @__PURE__ */ template(`<button type=button>`);
|
|
3749
|
-
var _tmpl$
|
|
3877
|
+
var _tmpl$37 = /* @__PURE__ */ template(`<div><button type=button></button><button type=button>`);
|
|
3750
3878
|
var Tabs = (props) => {
|
|
3751
3879
|
const styles = useStyles();
|
|
3752
3880
|
const {
|
|
@@ -3785,7 +3913,7 @@ var Tabs = (props) => {
|
|
|
3785
3913
|
insert(_el$, (() => {
|
|
3786
3914
|
var _c$ = memo(() => pipWindow().pipWindow !== null);
|
|
3787
3915
|
return () => _c$() ? null : (() => {
|
|
3788
|
-
var _el$3 = _tmpl$
|
|
3916
|
+
var _el$3 = _tmpl$37(), _el$4 = _el$3.firstChild, _el$5 = _el$4.nextSibling;
|
|
3789
3917
|
_el$3.style.setProperty("margin-top", "auto");
|
|
3790
3918
|
_el$4.$$click = handleDetachment;
|
|
3791
3919
|
insert(_el$4, createComponent(PiP, {}));
|
package/dist/index.js
CHANGED
|
@@ -30,7 +30,7 @@ var TanStackDevtoolsCore = class {
|
|
|
30
30
|
const mountTo = el;
|
|
31
31
|
const dispose = render(() => {
|
|
32
32
|
const _self$ = this;
|
|
33
|
-
this.#Component = lazy(() => import('./devtools/
|
|
33
|
+
this.#Component = lazy(() => import('./devtools/UUNAZSBD.js'));
|
|
34
34
|
const Devtools = this.#Component;
|
|
35
35
|
this.#eventBus = new ClientEventBus(this.#eventBusConfig);
|
|
36
36
|
this.#eventBus.start();
|
package/package.json
CHANGED
package/src/styles/use-styles.ts
CHANGED
|
@@ -1168,6 +1168,75 @@ const stylesFactory = (theme: DevtoolsStore['settings']['theme']) => {
|
|
|
1168
1168
|
text-transform: uppercase;
|
|
1169
1169
|
letter-spacing: 0.05em;
|
|
1170
1170
|
`,
|
|
1171
|
+
pluginMarketplaceFeatureBanner: css`
|
|
1172
|
+
margin-top: 1rem;
|
|
1173
|
+
padding: 1.25rem 1.5rem;
|
|
1174
|
+
background: ${t(
|
|
1175
|
+
'linear-gradient(135deg, #3b82f6 0%, #2563eb 100%)',
|
|
1176
|
+
'linear-gradient(135deg, #1e3a8a 0%, #1e40af 100%)',
|
|
1177
|
+
)};
|
|
1178
|
+
border-radius: 0.75rem;
|
|
1179
|
+
border: 1px solid ${t(colors.blue[400], colors.blue[800])};
|
|
1180
|
+
box-shadow:
|
|
1181
|
+
0 4px 6px -1px rgba(0, 0, 0, 0.1),
|
|
1182
|
+
0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
|
1183
|
+
`,
|
|
1184
|
+
pluginMarketplaceFeatureBannerContent: css`
|
|
1185
|
+
display: flex;
|
|
1186
|
+
flex-direction: column;
|
|
1187
|
+
gap: 0.75rem;
|
|
1188
|
+
`,
|
|
1189
|
+
pluginMarketplaceFeatureBannerTitle: css`
|
|
1190
|
+
font-size: 1.125rem;
|
|
1191
|
+
font-weight: 700;
|
|
1192
|
+
color: white;
|
|
1193
|
+
margin: 0;
|
|
1194
|
+
display: flex;
|
|
1195
|
+
align-items: center;
|
|
1196
|
+
gap: 0.5rem;
|
|
1197
|
+
`,
|
|
1198
|
+
pluginMarketplaceFeatureBannerIcon: css`
|
|
1199
|
+
width: 24px;
|
|
1200
|
+
height: 24px;
|
|
1201
|
+
display: inline-flex;
|
|
1202
|
+
`,
|
|
1203
|
+
pluginMarketplaceFeatureBannerText: css`
|
|
1204
|
+
font-size: 0.95rem;
|
|
1205
|
+
color: ${t('rgba(255, 255, 255, 0.95)', 'rgba(255, 255, 255, 0.9)')};
|
|
1206
|
+
line-height: 1.5;
|
|
1207
|
+
margin: 0;
|
|
1208
|
+
`,
|
|
1209
|
+
pluginMarketplaceFeatureBannerButton: css`
|
|
1210
|
+
display: inline-flex;
|
|
1211
|
+
align-items: center;
|
|
1212
|
+
gap: 0.5rem;
|
|
1213
|
+
padding: 0.625rem 1.25rem;
|
|
1214
|
+
background: white;
|
|
1215
|
+
color: ${colors.blue[600]};
|
|
1216
|
+
font-weight: 600;
|
|
1217
|
+
font-size: 0.95rem;
|
|
1218
|
+
border-radius: 0.5rem;
|
|
1219
|
+
border: none;
|
|
1220
|
+
cursor: pointer;
|
|
1221
|
+
transition: all 0.2s ease;
|
|
1222
|
+
text-decoration: none;
|
|
1223
|
+
align-self: flex-start;
|
|
1224
|
+
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
|
1225
|
+
|
|
1226
|
+
&:hover {
|
|
1227
|
+
background: ${t(colors.gray[50], colors.gray[100])};
|
|
1228
|
+
transform: translateY(-1px);
|
|
1229
|
+
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
|
|
1230
|
+
}
|
|
1231
|
+
|
|
1232
|
+
&:active {
|
|
1233
|
+
transform: translateY(0);
|
|
1234
|
+
}
|
|
1235
|
+
`,
|
|
1236
|
+
pluginMarketplaceFeatureBannerButtonIcon: css`
|
|
1237
|
+
width: 18px;
|
|
1238
|
+
height: 18px;
|
|
1239
|
+
`,
|
|
1171
1240
|
pluginMarketplaceCardDisabled: css`
|
|
1172
1241
|
opacity: 0.6;
|
|
1173
1242
|
filter: grayscale(0.3);
|
|
@@ -12,6 +12,31 @@ interface PluginSectionComponentProps {
|
|
|
12
12
|
onCardAction: (card: PluginCard) => void
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
+
const StarIcon = () => (
|
|
16
|
+
<svg
|
|
17
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
18
|
+
viewBox="0 0 24 24"
|
|
19
|
+
fill="currentColor"
|
|
20
|
+
>
|
|
21
|
+
<path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z" />
|
|
22
|
+
</svg>
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
const MailIcon = () => (
|
|
26
|
+
<svg
|
|
27
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
28
|
+
viewBox="0 0 24 24"
|
|
29
|
+
fill="none"
|
|
30
|
+
stroke="currentColor"
|
|
31
|
+
stroke-width="2"
|
|
32
|
+
stroke-linecap="round"
|
|
33
|
+
stroke-linejoin="round"
|
|
34
|
+
>
|
|
35
|
+
<rect x="2" y="4" width="20" height="16" rx="2" />
|
|
36
|
+
<path d="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7" />
|
|
37
|
+
</svg>
|
|
38
|
+
)
|
|
39
|
+
|
|
15
40
|
export const PluginSectionComponent = (props: PluginSectionComponentProps) => {
|
|
16
41
|
const styles = useStyles()
|
|
17
42
|
|
|
@@ -38,6 +63,33 @@ export const PluginSectionComponent = (props: PluginSectionComponentProps) => {
|
|
|
38
63
|
</div>
|
|
39
64
|
|
|
40
65
|
<Show when={!props.isCollapsed()}>
|
|
66
|
+
<Show when={props.section.id === 'featured'}>
|
|
67
|
+
<div class={styles().pluginMarketplaceFeatureBanner}>
|
|
68
|
+
<div class={styles().pluginMarketplaceFeatureBannerContent}>
|
|
69
|
+
<h4 class={styles().pluginMarketplaceFeatureBannerTitle}>
|
|
70
|
+
<span class={styles().pluginMarketplaceFeatureBannerIcon}>
|
|
71
|
+
<StarIcon />
|
|
72
|
+
</span>
|
|
73
|
+
Want to be featured here?
|
|
74
|
+
</h4>
|
|
75
|
+
<p class={styles().pluginMarketplaceFeatureBannerText}>
|
|
76
|
+
If you've built a plugin for TanStack Devtools and would like to
|
|
77
|
+
showcase it in the featured section, we'd love to hear from you!
|
|
78
|
+
Reach out to us to discuss partnership opportunities.
|
|
79
|
+
</p>
|
|
80
|
+
<a
|
|
81
|
+
href="mailto:partners+devtools@tanstack.com?subject=Featured%20Plugin%20Partnership%20Inquiry"
|
|
82
|
+
class={styles().pluginMarketplaceFeatureBannerButton}
|
|
83
|
+
>
|
|
84
|
+
<span class={styles().pluginMarketplaceFeatureBannerButtonIcon}>
|
|
85
|
+
<MailIcon />
|
|
86
|
+
</span>
|
|
87
|
+
Contact Us
|
|
88
|
+
</a>
|
|
89
|
+
</div>
|
|
90
|
+
</div>
|
|
91
|
+
</Show>
|
|
92
|
+
|
|
41
93
|
<div class={styles().pluginMarketplaceGrid}>
|
|
42
94
|
<For each={props.section.cards}>
|
|
43
95
|
{(card) => (
|
|
@@ -223,10 +223,11 @@ describe('groupIntoSections', () => {
|
|
|
223
223
|
|
|
224
224
|
const sections = groupIntoSections(cards)
|
|
225
225
|
|
|
226
|
-
expect(sections).toHaveLength(
|
|
227
|
-
expect(sections[0]?.id).toBe('
|
|
228
|
-
expect(sections[
|
|
229
|
-
expect(sections[
|
|
226
|
+
expect(sections).toHaveLength(2) // Featured (always present) + Active
|
|
227
|
+
expect(sections[0]?.id).toBe('featured')
|
|
228
|
+
expect(sections[1]?.id).toBe('active')
|
|
229
|
+
expect(sections[1]?.displayName).toBe('✓ Active Plugins')
|
|
230
|
+
expect(sections[1]?.cards).toHaveLength(1)
|
|
230
231
|
})
|
|
231
232
|
|
|
232
233
|
it('should group featured plugins', () => {
|
|
@@ -266,9 +267,11 @@ describe('groupIntoSections', () => {
|
|
|
266
267
|
|
|
267
268
|
const sections = groupIntoSections(cards)
|
|
268
269
|
|
|
269
|
-
expect(sections).toHaveLength(
|
|
270
|
-
expect(sections[0]?.id).toBe('
|
|
271
|
-
expect(sections.
|
|
270
|
+
expect(sections).toHaveLength(2) // Featured (always present) + Active
|
|
271
|
+
expect(sections[0]?.id).toBe('featured')
|
|
272
|
+
expect(sections[1]?.id).toBe('active')
|
|
273
|
+
expect(sections[0]?.cards).toHaveLength(0) // Featured section empty
|
|
274
|
+
expect(sections[1]?.cards).toHaveLength(1) // Active has the plugin
|
|
272
275
|
})
|
|
273
276
|
|
|
274
277
|
it('should group available plugins', () => {
|
|
@@ -286,9 +289,10 @@ describe('groupIntoSections', () => {
|
|
|
286
289
|
|
|
287
290
|
const sections = groupIntoSections(cards)
|
|
288
291
|
|
|
289
|
-
expect(sections).toHaveLength(
|
|
290
|
-
expect(sections[0]?.id).toBe('
|
|
291
|
-
expect(sections[
|
|
292
|
+
expect(sections).toHaveLength(2) // Featured (always present) + Available
|
|
293
|
+
expect(sections[0]?.id).toBe('featured')
|
|
294
|
+
expect(sections[1]?.id).toBe('available')
|
|
295
|
+
expect(sections[1]?.displayName).toBe('Available Plugins')
|
|
292
296
|
})
|
|
293
297
|
|
|
294
298
|
it('should not include featured plugins in available section', () => {
|
|
@@ -345,8 +349,8 @@ describe('groupIntoSections', () => {
|
|
|
345
349
|
const sections = groupIntoSections(cards)
|
|
346
350
|
|
|
347
351
|
expect(sections).toHaveLength(3)
|
|
348
|
-
expect(sections[0]?.id).toBe('
|
|
349
|
-
expect(sections[1]?.id).toBe('
|
|
352
|
+
expect(sections[0]?.id).toBe('featured')
|
|
353
|
+
expect(sections[1]?.id).toBe('active')
|
|
350
354
|
expect(sections[2]?.id).toBe('available')
|
|
351
355
|
})
|
|
352
356
|
|
|
@@ -365,12 +369,16 @@ describe('groupIntoSections', () => {
|
|
|
365
369
|
|
|
366
370
|
const sections = groupIntoSections(cards)
|
|
367
371
|
|
|
368
|
-
expect(sections).toHaveLength(
|
|
372
|
+
expect(sections).toHaveLength(1) // Only featured section (always present, empty)
|
|
373
|
+
expect(sections[0]?.id).toBe('featured')
|
|
374
|
+
expect(sections[0]?.cards).toHaveLength(0)
|
|
369
375
|
})
|
|
370
376
|
|
|
371
377
|
it('should handle empty card array', () => {
|
|
372
378
|
const sections = groupIntoSections([])
|
|
373
|
-
expect(sections).toHaveLength(
|
|
379
|
+
expect(sections).toHaveLength(1) // Featured section always present
|
|
380
|
+
expect(sections[0]?.id).toBe('featured')
|
|
381
|
+
expect(sections[0]?.cards).toHaveLength(0)
|
|
374
382
|
})
|
|
375
383
|
})
|
|
376
384
|
|
|
@@ -201,6 +201,20 @@ export const groupIntoSections = (
|
|
|
201
201
|
): Array<PluginSection> => {
|
|
202
202
|
const sections: Array<PluginSection> = []
|
|
203
203
|
|
|
204
|
+
// Add Featured section first - always show this section
|
|
205
|
+
const featuredCards = allCards.filter(
|
|
206
|
+
(c) =>
|
|
207
|
+
c.metadata?.featured &&
|
|
208
|
+
c.actionType !== 'already-installed' &&
|
|
209
|
+
c.isCurrentFramework, // Only show featured plugins for current framework
|
|
210
|
+
)
|
|
211
|
+
// Always add featured section, even if no cards to show the partner banner
|
|
212
|
+
sections.push({
|
|
213
|
+
id: 'featured',
|
|
214
|
+
displayName: '⭐ Featured',
|
|
215
|
+
cards: featuredCards,
|
|
216
|
+
})
|
|
217
|
+
|
|
204
218
|
// Add Active Plugins section
|
|
205
219
|
const activeCards = allCards.filter(
|
|
206
220
|
(c) => c.actionType === 'already-installed' && c.isRegistered,
|
|
@@ -213,21 +227,6 @@ export const groupIntoSections = (
|
|
|
213
227
|
})
|
|
214
228
|
}
|
|
215
229
|
|
|
216
|
-
// Add Featured section
|
|
217
|
-
const featuredCards = allCards.filter(
|
|
218
|
-
(c) =>
|
|
219
|
-
c.metadata?.featured &&
|
|
220
|
-
c.actionType !== 'already-installed' &&
|
|
221
|
-
c.isCurrentFramework, // Only show featured plugins for current framework
|
|
222
|
-
)
|
|
223
|
-
if (featuredCards.length > 0) {
|
|
224
|
-
sections.push({
|
|
225
|
-
id: 'featured',
|
|
226
|
-
displayName: '⭐ Featured',
|
|
227
|
-
cards: featuredCards,
|
|
228
|
-
})
|
|
229
|
-
}
|
|
230
|
-
|
|
231
230
|
// Add Available section - all plugins for current framework (TanStack + third-party)
|
|
232
231
|
const availableCards = allCards.filter(
|
|
233
232
|
(c) =>
|
|
@@ -212,6 +212,35 @@ const PLUGIN_REGISTRY: Record<string, PluginMetadata> = {
|
|
|
212
212
|
// THIRD-PARTY PLUGINS - Examples
|
|
213
213
|
// ==========================================
|
|
214
214
|
// External contributors can add their plugins below!
|
|
215
|
+
|
|
216
|
+
// Dimano — Prefetch Heatmap for TanStack Router
|
|
217
|
+
'@dimano/ts-devtools-plugin-prefetch-heatmap': {
|
|
218
|
+
packageName: '@dimano/ts-devtools-plugin-prefetch-heatmap',
|
|
219
|
+
title: 'Prefetch Heatmap',
|
|
220
|
+
description:
|
|
221
|
+
'Visualize TanStack Router prefetch intent, hits, and waste with a color overlay and a live metrics panel.',
|
|
222
|
+
requires: {
|
|
223
|
+
packageName: '@tanstack/react-router',
|
|
224
|
+
minVersion: '1.0.0',
|
|
225
|
+
},
|
|
226
|
+
// default export registers the plugin
|
|
227
|
+
pluginImport: {
|
|
228
|
+
importName: 'registerPrefetchHeatmapPlugin',
|
|
229
|
+
type: 'function',
|
|
230
|
+
},
|
|
231
|
+
// helps the host match your plugin deterministically
|
|
232
|
+
pluginId: 'prefetch-heatmap',
|
|
233
|
+
// show a nice card in the marketplace
|
|
234
|
+
logoUrl:
|
|
235
|
+
'https://raw.githubusercontent.com/dimitrianoudi/tanstack-prefetch-heatmap/main/assets/prefetch-heatmap-card.png',
|
|
236
|
+
docsUrl:
|
|
237
|
+
'https://github.com/dimitrianoudi/tanstack-prefetch-heatmap#prefetch-heatmap-devtools-plugin',
|
|
238
|
+
repoUrl: 'https://github.com/dimitrianoudi/tanstack-prefetch-heatmap',
|
|
239
|
+
author: 'Dimitris Anoudis (@dimitrianoudi)',
|
|
240
|
+
framework: 'react',
|
|
241
|
+
isNew: true,
|
|
242
|
+
tags: ['Router', 'Prefetch', 'Analytics', 'Overlay', 'TanStack'],
|
|
243
|
+
},
|
|
215
244
|
}
|
|
216
245
|
|
|
217
246
|
/**
|