initial commit

This commit is contained in:
René Schober
2026-03-13 06:23:06 +01:00
commit 4e34270786
314 changed files with 37280 additions and 0 deletions

View File

@@ -0,0 +1,157 @@
#!/usr/bin/env node
/**
* Get complete component documentation (MDX) for HeroUI Native components.
*
* Usage:
* node get_component_docs.mjs Button
* node get_component_docs.mjs Button Card TextField
*
* Output:
* MDX documentation including imports, usage, variants, props, examples
*/
const API_BASE = process.env.HEROUI_NATIVE_API_BASE || "https://native-mcp-api.heroui.com";
const FALLBACK_BASE = "https://v3.heroui.com";
const APP_PARAM = "app=native-skills";
/**
* Convert PascalCase to kebab-case.
*/
function toKebabCase(name) {
return name
.replace(/([a-z])([A-Z])/g, "$1-$2")
.replace(/([A-Z])([A-Z][a-z])/g, "$1-$2")
.toLowerCase();
}
/**
* Fetch data from HeroUI Native API with app parameter for analytics.
*/
async function fetchApi(endpoint, method = "GET", body = null) {
const separator = endpoint.includes("?") ? "&" : "?";
const url = `${API_BASE}${endpoint}${separator}${APP_PARAM}`;
try {
const options = {
headers: {
"Content-Type": "application/json",
"User-Agent": "HeroUI-Native-Skill/1.0",
},
method,
signal: AbortSignal.timeout(30000),
};
if (body) {
options.body = JSON.stringify(body);
}
const response = await fetch(url, options);
if (!response.ok) {
return null;
}
return await response.json();
} catch {
return null;
}
}
/**
* Fetch MDX directly from v3.heroui.com as fallback.
*/
async function fetchFallback(component) {
const kebabName = toKebabCase(component);
const url = `${FALLBACK_BASE}/docs/native/components/${kebabName}.mdx`;
try {
const response = await fetch(url, {
headers: { "User-Agent": "HeroUI-Native-Skill/1.0" },
signal: AbortSignal.timeout(30000),
});
if (!response.ok) {
return { component, error: `Failed to fetch docs for ${component}` };
}
const content = await response.text();
return {
component,
content,
contentType: "mdx",
source: "fallback",
url,
};
} catch {
return { component, error: `Failed to fetch docs for ${component}` };
}
}
/**
* Main function to get component documentation.
*/
async function main() {
const args = process.argv.slice(2);
if (args.length === 0) {
console.error("Usage: node get_component_docs.mjs <Component1> [Component2] ...");
console.error("Example: node get_component_docs.mjs Button Card");
process.exit(1);
}
const components = args;
// Try API first - use POST /v1/components/docs for batch requests
console.error(`# Fetching Native docs for: ${components.join(", ")}...`);
const data = await fetchApi("/v1/components/docs", "POST", { components });
if (data && data.results) {
// Output results
if (data.results.length === 1) {
// Single component - output content directly for easier reading
const result = data.results[0];
if (result.content) {
console.log(result.content);
} else if (result.error) {
console.error(`# Error for ${result.component}: ${result.error}`);
console.log(JSON.stringify(result, null, 2));
} else {
console.log(JSON.stringify(result, null, 2));
}
} else {
// Multiple components - output as JSON array
console.log(JSON.stringify(data, null, 2));
}
return;
}
// Fallback to individual component fetches
console.error("# API failed, using fallback...");
const results = [];
for (const component of components) {
const result = await fetchFallback(component);
results.push(result);
}
// Output results
if (results.length === 1) {
// Single component - output content directly for easier reading
const result = results[0];
if (result.content) {
console.log(result.content);
} else {
console.log(JSON.stringify(result, null, 2));
}
} else {
// Multiple components - output as JSON array
console.log(JSON.stringify(results, null, 2));
}
}
main();

View File

@@ -0,0 +1,154 @@
#!/usr/bin/env node
/**
* Get non-component HeroUI Native documentation (guides, theming, releases).
*
* Usage:
* node get_docs.mjs /docs/native/getting-started/theming
* node get_docs.mjs /docs/native/releases/beta-12
*
* Output:
* MDX documentation content
*
* Note: For component docs, use get_component_docs.mjs instead.
*/
const API_BASE = process.env.HEROUI_NATIVE_API_BASE || "https://native-mcp-api.heroui.com";
const FALLBACK_BASE = "https://v3.heroui.com";
const APP_PARAM = "app=native-skills";
/**
* Fetch documentation from HeroUI Native API.
* Uses v1 endpoint pattern: /v1/docs/:path
*/
async function fetchApi(path) {
// The v1 API expects path without /docs/ prefix
// Input: /docs/native/getting-started/theming
// API expects: native/getting-started/theming (route is /v1/docs/:path(*))
let apiPath = path.startsWith("/docs/")
? path.slice(6) // Remove /docs/ prefix
: path.startsWith("/")
? path.slice(1) // Remove leading /
: path;
const separator = "?";
const url = `${API_BASE}/v1/docs/${apiPath}${separator}${APP_PARAM}`;
try {
const response = await fetch(url, {
headers: { "User-Agent": "HeroUI-Native-Skill/1.0" },
signal: AbortSignal.timeout(30000),
});
if (!response.ok) {
console.error(`# API Error: HTTP ${response.status}`);
return null;
}
return await response.json();
} catch (error) {
console.error(`# API Error: ${error.message}`);
return null;
}
}
/**
* Fetch MDX directly from v3.heroui.com as fallback.
*/
async function fetchFallback(path) {
// Ensure path starts with /docs and ends with .mdx
let cleanPath = path.replace(/^\//, "");
if (!cleanPath.endsWith(".mdx")) {
cleanPath = `${cleanPath}.mdx`;
}
const url = `${FALLBACK_BASE}/${cleanPath}`;
try {
const response = await fetch(url, {
headers: { "User-Agent": "HeroUI-Native-Skill/1.0" },
signal: AbortSignal.timeout(30000),
});
if (!response.ok) {
return { error: `HTTP ${response.status}: ${response.statusText}`, path };
}
const content = await response.text();
return {
content,
contentType: "mdx",
path,
source: "fallback",
url,
};
} catch (error) {
return { error: `Fetch Error: ${error.message}`, path };
}
}
/**
* Main function to get documentation for specified path.
*/
async function main() {
const args = process.argv.slice(2);
if (args.length === 0) {
console.error("Usage: node get_docs.mjs <path>");
console.error("Example: node get_docs.mjs /docs/native/getting-started/theming");
console.error();
console.error("Available paths include:");
console.error(" /docs/native/getting-started/theming");
console.error(" /docs/native/getting-started/colors");
console.error(" /docs/native/getting-started/styling");
console.error(" /docs/native/releases/beta-12");
console.error();
console.error("Note: For component docs, use get_component_docs.mjs instead.");
process.exit(1);
}
const path = args[0];
// Check if user is trying to get component docs
if (path.includes("/components/")) {
console.error("# Warning: Use get_component_docs.mjs for component documentation.");
const componentName = path.split("/").pop().replace(".mdx", "");
const titleCase = componentName.charAt(0).toUpperCase() + componentName.slice(1);
console.error(`# Example: node get_component_docs.mjs ${titleCase}`);
}
// Validate Native path
if (!path.startsWith("/docs/native/")) {
console.error("# Warning: Native documentation paths should start with /docs/native/");
console.error(`# Provided path: ${path}`);
}
console.error(`# Fetching Native documentation for ${path}...`);
// Try API first
const data = await fetchApi(path);
if (data && data.content) {
data.source = "api";
console.log(data.content);
return;
}
// Fallback to direct fetch
console.error("# API failed, using fallback...");
const fallbackData = await fetchFallback(path);
if (fallbackData.content) {
console.log(fallbackData.content);
} else {
console.log(JSON.stringify(fallbackData, null, 2));
process.exit(1);
}
}
main();

View File

@@ -0,0 +1,222 @@
#!/usr/bin/env node
/**
* Get theme variables and design tokens for HeroUI Native.
*
* Usage:
* node get_theme.mjs
*
* Output:
* Theme variables organized by light/dark with HSL color format
*/
const API_BASE = process.env.HEROUI_NATIVE_API_BASE || "https://native-mcp-api.heroui.com";
const APP_PARAM = "app=native-skills";
// Fallback theme reference when API is unavailable
const FALLBACK_THEME = {
borderRadius: {
full: 9999,
lg: 12,
md: 8,
sm: 6,
},
dark: {
colors: [
{
category: "base",
name: "--color-background",
value: "hsl(0, 0%, 14.5%)",
},
{
category: "semantic",
name: "--color-foreground",
value: "hsl(0, 0%, 98.4%)",
},
{
category: "semantic",
name: "--color-accent",
value: "hsl(264.1, 100%, 55.1%)",
},
{
category: "status",
name: "--color-danger",
value: "hsl(25.3, 100%, 63.7%)",
},
{
category: "status",
name: "--color-success",
value: "hsl(163.2, 100%, 76.5%)",
},
{
category: "status",
name: "--color-warning",
value: "hsl(86.0, 100%, 79.5%)",
},
],
},
latestVersion: "beta",
light: {
colors: [
{
category: "base",
name: "--color-background",
value: "hsl(0, 0%, 100%)",
},
{
category: "semantic",
name: "--color-foreground",
value: "hsl(285.89, 5.9%, 21.03%)",
},
{
category: "semantic",
name: "--color-accent",
value: "hsl(253.83, 100%, 62.04%)",
},
{
category: "status",
name: "--color-danger",
value: "hsl(25.74, 100%, 65.32%)",
},
{
category: "status",
name: "--color-success",
value: "hsl(150.81, 100%, 73.29%)",
},
{
category: "status",
name: "--color-warning",
value: "hsl(72.33, 100%, 78.19%)",
},
],
},
note: "This is a fallback. For complete theme variables, ensure the API is accessible.",
opacity: {
disabled: 0.4,
hover: 0.8,
pressed: 0.6,
},
source: "fallback",
theme: "default",
};
/**
* Fetch data from HeroUI Native API with app parameter for analytics.
*/
async function fetchApi(endpoint) {
const separator = endpoint.includes("?") ? "&" : "?";
const url = `${API_BASE}${endpoint}${separator}${APP_PARAM}`;
try {
const response = await fetch(url, {
headers: { "User-Agent": "HeroUI-Native-Skill/1.0" },
signal: AbortSignal.timeout(30000),
});
if (!response.ok) {
console.error(`# API Error: HTTP ${response.status}`);
return null;
}
return await response.json();
} catch (error) {
console.error(`# API Error: ${error.message}`);
return null;
}
}
/**
* Format colors grouped by category.
*/
function formatColors(colors) {
const grouped = {};
for (const color of colors) {
const category = color.category || "semantic";
if (!grouped[category]) {
grouped[category] = [];
}
grouped[category].push(color);
}
const lines = [];
for (const [category, tokens] of Object.entries(grouped)) {
lines.push(` /* ${category.charAt(0).toUpperCase() + category.slice(1)} Colors */`);
for (const token of tokens) {
const name = token.name || "";
const value = token.value || "";
lines.push(` ${name}: ${value};`);
}
lines.push("");
}
return lines.join("\n");
}
/**
* Main function to get theme variables.
*/
async function main() {
console.error("# Fetching Native theme variables...");
const rawData = await fetchApi("/v1/themes/variables?theme=default");
let data;
let version;
if (!rawData) {
console.error("# API failed, using fallback theme reference...");
data = FALLBACK_THEME;
version = FALLBACK_THEME.latestVersion || "unknown";
} else {
// Handle API response format
data = rawData;
version = rawData.latestVersion || "unknown";
}
// Output as formatted structure for readability
console.log("/* HeroUI Native Theme Variables */");
console.log(`/* Theme: ${data.theme || "default"} */`);
console.log(`/* Version: ${version} */`);
console.log();
// Light mode colors
if (data.light && data.light.colors) {
console.log("/* Light Mode Colors */");
console.log(formatColors(data.light.colors));
}
// Dark mode colors
if (data.dark && data.dark.colors) {
console.log("/* Dark Mode Colors */");
console.log(formatColors(data.dark.colors));
}
// Border radius
if (data.borderRadius) {
console.log("/* Border Radius */");
for (const [key, value] of Object.entries(data.borderRadius)) {
console.log(` --radius-${key}: ${value};`);
}
console.log();
}
// Opacity
if (data.opacity) {
console.log("/* Opacity */");
for (const [key, value] of Object.entries(data.opacity)) {
console.log(` --opacity-${key}: ${value};`);
}
console.log();
}
// Also output raw JSON to stderr for programmatic use
console.error("\n# Raw JSON output:");
console.error(JSON.stringify(rawData || data, null, 2));
}
main();

View File

@@ -0,0 +1,134 @@
#!/usr/bin/env node
/**
* List all available HeroUI Native components.
*
* Usage:
* node list_components.mjs
*
* Output:
* JSON with components array, latestVersion, and count
*/
const API_BASE = process.env.HEROUI_NATIVE_API_BASE || "https://native-mcp-api.heroui.com";
const APP_PARAM = "app=native-skills";
const LLMS_TXT_URL = "https://v3.heroui.com/native/llms.txt";
/**
* Fetch data from HeroUI Native API with app parameter for analytics.
*/
async function fetchApi(endpoint) {
const separator = endpoint.includes("?") ? "&" : "?";
const url = `${API_BASE}${endpoint}${separator}${APP_PARAM}`;
try {
const response = await fetch(url, {
headers: { "User-Agent": "HeroUI-Native-Skill/1.0" },
signal: AbortSignal.timeout(30000),
});
if (!response.ok) {
console.error(`HTTP Error ${response.status}: ${response.statusText}`);
return null;
}
return await response.json();
} catch (error) {
console.error(`API Error: ${error.message}`);
return null;
}
}
/**
* Fetch component list from llms.txt fallback URL.
*/
async function fetchFallback() {
try {
const response = await fetch(LLMS_TXT_URL, {
headers: { "User-Agent": "HeroUI-Native-Skill/1.0" },
signal: AbortSignal.timeout(30000),
});
if (!response.ok) {
return null;
}
const content = await response.text();
// Parse markdown to extract component names from pattern: - [ComponentName](url)
// Look for links under the Components section (### Components)
const components = [];
let inComponentsSection = false;
for (const line of content.split("\n")) {
// Check if we're entering the Components section (uses ### header)
if (line.trim() === "### Components") {
inComponentsSection = true;
continue;
}
// Check if we're leaving the Components section (another ### header)
if (inComponentsSection && line.trim().startsWith("### ")) {
break;
}
// Extract component name from markdown link pattern
// Match: - [ComponentName](https://v3.heroui.com/docs/native/components/component-name)
// Skip "All Components" which links to /components without a specific component
if (inComponentsSection) {
const match = line.match(
/^\s*-\s*\[([^\]]+)\]\(https:\/\/v3\.heroui\.com\/docs\/native\/components\/[a-z]/,
);
if (match) {
components.push(match[1]);
}
}
}
if (components.length > 0) {
console.error(`# Using fallback: ${LLMS_TXT_URL}`);
return {
components: components.sort(),
count: components.length,
latestVersion: "unknown",
};
}
return null;
} catch (error) {
console.error(`Fallback Error: ${error.message}`);
return null;
}
}
/**
* Main function to list all available HeroUI Native components.
*/
async function main() {
let data = await fetchApi("/v1/components");
// Check if API returned valid data with components
if (!data || !data.components || data.components.length === 0) {
console.error("# API returned no components, trying fallback...");
data = await fetchFallback();
}
if (!data || !data.components || data.components.length === 0) {
console.error("Error: Failed to fetch component list from API and fallback");
process.exit(1);
}
// Output formatted JSON
console.log(JSON.stringify(data, null, 2));
// Print summary to stderr for human readability
console.error(
`\n# Found ${data.components.length} Native components (${data.latestVersion || "unknown"})`,
);
}
main();