This commit is contained in:
2026-01-25 14:43:14 +01:00
parent f965340abe
commit 17684e7e2e
7 changed files with 778 additions and 28 deletions

25
Caddyfile Normal file
View File

@@ -0,0 +1,25 @@
:80 {
root * /srv
# Enable gzip compression
encode gzip
# Handle client-side routing - try file, then index.html
try_files {path} /index.html
# Serve static files
file_server
# Cache static assets
@static {
path *.js *.css *.png *.jpg *.jpeg *.gif *.ico *.svg *.woff *.woff2 *.ttf *.eot
}
header @static Cache-Control "public, max-age=31536000, immutable"
# Security headers
header {
X-Frame-Options "SAMEORIGIN"
X-Content-Type-Options "nosniff"
X-XSS-Protection "1; mode=block"
}
}

View File

@@ -16,17 +16,17 @@ COPY . .
# Build the application # Build the application
RUN npm run build RUN npm run build
# Production stage # Production stage - Using Caddy
FROM nginx:alpine AS production FROM caddy:2-alpine AS production
# Copy custom nginx config
COPY nginx.conf /etc/nginx/conf.d/default.conf
# Copy built assets from builder stage # Copy built assets from builder stage
COPY --from=builder /app/dist /usr/share/nginx/html COPY --from=builder /app/dist /srv
# Copy Caddyfile
COPY Caddyfile /etc/caddy/Caddyfile
# Expose port 80 # Expose port 80
EXPOSE 80 EXPOSE 80
# Start nginx # Start Caddy
CMD ["nginx", "-g", "daemon off;"] CMD ["caddy", "run", "--config", "/etc/caddy/Caddyfile"]

View File

@@ -76,26 +76,24 @@ else
print_status "Caddy network exists" print_status "Caddy network exists"
fi fi
# Step 4: Update Caddy configuration # Step 4: Show Caddy configuration to add
echo "" echo ""
echo -e "${BLUE}Step 4: Updating Caddy configuration...${NC}" echo -e "${BLUE}Step 4: Caddy configuration...${NC}"
# Check if Traceability entry already exists in Caddyfile # Check if Traceability entry already exists in Caddyfile
if grep -q "Traceability.nabd-co.com" "$CADDY_DIR/Caddyfile" 2>/dev/null; then if grep -q "Traceability.nabd-co.com" "$CADDY_DIR/Caddyfile" 2>/dev/null; then
print_status "Caddy configuration already exists" print_status "Caddy configuration already exists in Caddyfile"
else else
# Append Traceability configuration to Caddyfile print_warning "Add this entry to your Caddyfile at $CADDY_DIR/Caddyfile:"
cat >> "$CADDY_DIR/Caddyfile" << 'EOF' echo ""
echo -e "${YELLOW}# -------------------------"
# ------------------------- echo "# Traceability Matrix Proxy"
# Traceability Matrix Proxy echo "# -------------------------"
# ------------------------- echo "Traceability.nabd-co.com {"
Traceability.nabd-co.com { echo " reverse_proxy traceability_web:80"
reverse_proxy traceability_web:80 echo " encode gzip"
encode gzip echo -e "}${NC}"
} echo ""
EOF
print_status "Added Traceability configuration to Caddyfile"
fi fi
# Step 5: Build and start the application # Step 5: Build and start the application

View File

@@ -8,11 +8,8 @@ services:
container_name: traceability_web container_name: traceability_web
restart: always restart: always
networks: networks:
- caddy_network - caddy_default
labels:
- "traefik.enable=false"
networks: networks:
caddy_network: caddy_default:
external: true external: true
name: caddy_default

View File

@@ -8,6 +8,7 @@ import DocumentationPage from "./pages/DocumentationPage";
import AnalysisPage from "./pages/AnalysisPage"; import AnalysisPage from "./pages/AnalysisPage";
import ALMTypePage from "./pages/ALMTypePage"; import ALMTypePage from "./pages/ALMTypePage";
import TraceabilityMatrixPage from "./pages/TraceabilityMatrixPage"; import TraceabilityMatrixPage from "./pages/TraceabilityMatrixPage";
import ESPIDFHelperPage from "./pages/ESPIDFHelperPage";
import NotFound from "./pages/NotFound"; import NotFound from "./pages/NotFound";
const queryClient = new QueryClient(); const queryClient = new QueryClient();
@@ -23,6 +24,7 @@ const App = () => (
<Route path="/documentation" element={<DocumentationPage />} /> <Route path="/documentation" element={<DocumentationPage />} />
<Route path="/analysis" element={<AnalysisPage />} /> <Route path="/analysis" element={<AnalysisPage />} />
<Route path="/matrix" element={<TraceabilityMatrixPage />} /> <Route path="/matrix" element={<TraceabilityMatrixPage />} />
<Route path="/esp-idf" element={<ESPIDFHelperPage />} />
<Route path="/alm/:type" element={<ALMTypePage />} /> <Route path="/alm/:type" element={<ALMTypePage />} />
{/* ADD ALL CUSTOM ROUTES ABOVE THE CATCH-ALL "*" ROUTE */} {/* ADD ALL CUSTOM ROUTES ABOVE THE CATCH-ALL "*" ROUTE */}
<Route path="*" element={<NotFound />} /> <Route path="*" element={<NotFound />} />

View File

@@ -16,6 +16,7 @@ import {
LayoutDashboard, LayoutDashboard,
ChevronDown, ChevronDown,
ChevronRight, ChevronRight,
Cpu,
} from "lucide-react"; } from "lucide-react";
import { NavLink } from "@/components/NavLink"; import { NavLink } from "@/components/NavLink";
import { useLocation } from "react-router-dom"; import { useLocation } from "react-router-dom";
@@ -37,6 +38,7 @@ const mainItems = [
{ title: "Traceability Matrix", url: "/matrix", icon: GitBranch }, { title: "Traceability Matrix", url: "/matrix", icon: GitBranch },
{ title: "Documentation", url: "/documentation", icon: BookOpen }, { title: "Documentation", url: "/documentation", icon: BookOpen },
{ title: "Gap Analysis", url: "/analysis", icon: Search }, { title: "Gap Analysis", url: "/analysis", icon: Search },
{ title: "ESP-IDF Helper", url: "/esp-idf", icon: Cpu },
]; ];
const almItems = [ const almItems = [

View File

@@ -0,0 +1,726 @@
import { useState } from "react";
import { AppLayout } from "@/components/layout/AppLayout";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { ScrollArea } from "@/components/ui/scroll-area";
import { Input } from "@/components/ui/input";
import {
Cpu,
Wifi,
Bluetooth,
Shield,
Zap,
HardDrive,
Code,
Terminal,
Search,
ExternalLink,
Layers,
Radio,
Database,
Lock,
RefreshCw,
Settings,
Clock,
Thermometer,
CircuitBoard,
Cable,
Gauge,
Monitor
} from "lucide-react";
import { cn } from "@/lib/utils";
// ESP-IDF V5.4 Data
const supportedChips = [
{ name: "ESP32", cores: "Dual-core Xtensa LX6", flash: "Up to 16MB", ram: "520KB SRAM", wifi: true, bt: "Classic + BLE", status: "Stable" },
{ name: "ESP32-S2", cores: "Single-core Xtensa LX7", flash: "Up to 16MB", ram: "320KB SRAM", wifi: true, bt: null, status: "Stable" },
{ name: "ESP32-S3", cores: "Dual-core Xtensa LX7", flash: "Up to 16MB", ram: "512KB SRAM + 8MB PSRAM", wifi: true, bt: "BLE 5.0", status: "Stable" },
{ name: "ESP32-C2", cores: "Single-core RISC-V", flash: "Up to 4MB", ram: "272KB SRAM", wifi: true, bt: "BLE 5.0", status: "Stable" },
{ name: "ESP32-C3", cores: "Single-core RISC-V", flash: "Up to 16MB", ram: "400KB SRAM", wifi: true, bt: "BLE 5.0", status: "Stable" },
{ name: "ESP32-C6", cores: "Single-core RISC-V", flash: "Up to 16MB", ram: "512KB SRAM", wifi: "WiFi 6", bt: "BLE 5.0 + 802.15.4", status: "Stable" },
{ name: "ESP32-H2", cores: "Single-core RISC-V", flash: "Up to 4MB", ram: "320KB SRAM", wifi: false, bt: "BLE 5.0 + 802.15.4", status: "Stable" },
{ name: "ESP32-P4", cores: "Dual-core RISC-V HP + LP", flash: "External", ram: "768KB + 8KB LP", wifi: false, bt: false, status: "Preview" },
];
const peripherals = [
{
name: "GPIO",
icon: CircuitBoard,
description: "General Purpose Input/Output pins with interrupt support",
apis: ["gpio_config()", "gpio_set_level()", "gpio_get_level()", "gpio_install_isr_service()", "gpio_isr_handler_add()"],
features: ["Pull-up/Pull-down resistors", "Interrupt on edge/level", "RTC GPIO support", "Sleep retention (v5.4)"]
},
{
name: "SPI",
icon: Cable,
description: "Serial Peripheral Interface for high-speed communication",
apis: ["spi_bus_initialize()", "spi_bus_add_device()", "spi_device_transmit()", "spi_device_queue_trans()"],
features: ["Master/Slave modes", "DMA support", "Up to 80MHz", "Multiple devices per bus", "Sleep retention (v5.4)"]
},
{
name: "I2C",
icon: Cable,
description: "Inter-Integrated Circuit for sensor communication",
apis: ["i2c_param_config()", "i2c_driver_install()", "i2c_master_write_read_device()", "i2c_master_cmd_begin()"],
features: ["Master/Slave modes", "Standard (100kHz) and Fast (400kHz)", "Clock stretching", "LP-I2C on C6/P4"]
},
{
name: "UART",
icon: Terminal,
description: "Universal Asynchronous Receiver/Transmitter",
apis: ["uart_driver_install()", "uart_param_config()", "uart_write_bytes()", "uart_read_bytes()"],
features: ["Hardware flow control", "Ring buffer", "Pattern detection", "RS-485 support"]
},
{
name: "ADC",
icon: Gauge,
description: "Analog to Digital Converter (12-bit resolution)",
apis: ["adc_oneshot_new_unit()", "adc_oneshot_read()", "adc_cali_create_scheme_curve_fitting()", "adc_continuous_start()"],
features: ["Oneshot & Continuous modes", "Hardware calibration", "Attenuation settings", "LP-ADC on C6/P4"]
},
{
name: "LEDC (PWM)",
icon: Zap,
description: "LED Controller for PWM signal generation",
apis: ["ledc_timer_config()", "ledc_channel_config()", "ledc_set_duty()", "ledc_update_duty()", "ledc_fade_start()"],
features: ["High-speed & low-speed modes", "Hardware fade", "Multiple channels", "Up to 40MHz"]
},
{
name: "Timer",
icon: Clock,
description: "Hardware timers for precise timing operations",
apis: ["gptimer_new_timer()", "gptimer_set_alarm_action()", "gptimer_start()", "esp_timer_create()"],
features: ["64-bit general purpose timers", "Alarm on match", "Auto-reload", "High-resolution esp_timer"]
},
{
name: "Temperature Sensor",
icon: Thermometer,
description: "Built-in temperature sensor",
apis: ["temperature_sensor_install()", "temperature_sensor_enable()", "temperature_sensor_get_celsius()"],
features: ["On-chip temperature", "-10°C to 80°C range", "Low power consumption"]
},
];
const networkingFeatures = [
{
name: "WiFi",
icon: Wifi,
description: "802.11 b/g/n wireless connectivity",
apis: ["esp_wifi_init()", "esp_wifi_set_mode()", "esp_wifi_set_config()", "esp_wifi_connect()", "esp_wifi_scan_start()"],
modes: ["Station (STA)", "SoftAP", "STA+AP", "Promiscuous", "WiFi 6 (C6 only)"],
features: ["WPA3 security", "FTM calibration (v5.4)", "Improved coex power (v5.4)", "ESP-NOW protocol"]
},
{
name: "Bluetooth",
icon: Bluetooth,
description: "Bluetooth Classic and BLE support",
apis: ["esp_bt_controller_init()", "esp_bluedroid_init()", "esp_ble_gap_start_advertising()", "nimble_port_init()"],
modes: ["Classic BR/EDR (ESP32/S3)", "BLE 5.0", "Mesh", "HID", "A2DP/AVRCP"],
features: ["Dual-mode", "Cover Art AVRCP (v5.4)", "NimBLE 1.7.0 (v5.4)", "Device ID Profile"]
},
{
name: "Thread / Zigbee",
icon: Radio,
description: "802.15.4 mesh networking protocols",
apis: ["esp_openthread_init()", "esp_zb_init()", "esp_zb_start()"],
modes: ["Thread Border Router", "Zigbee Coordinator/Router/End Device"],
features: ["Matter support", "TREL (v5.4)", "Zigbee 1.6.x", "RCP over USB (v5.4)"]
},
{
name: "ESP-NETIF",
icon: Layers,
description: "Network interface abstraction layer",
apis: ["esp_netif_init()", "esp_netif_create_default_wifi_sta()", "esp_netif_get_ip_info()"],
modes: ["WiFi", "Ethernet", "PPP", "SLIP"],
features: ["DHCP client/server", "Static IP", "IPv4/IPv6", "DNS"]
},
];
const protocolsLibraries = [
{
category: "HTTP/HTTPS",
items: [
{ name: "esp_http_client", description: "HTTP client for REST APIs", apis: ["esp_http_client_init()", "esp_http_client_perform()"] },
{ name: "esp_http_server", description: "HTTP server for web dashboards", apis: ["httpd_start()", "httpd_register_uri_handler()"] },
]
},
{
category: "MQTT",
items: [
{ name: "esp_mqtt", description: "MQTT v3.1.1/v5.0 client", apis: ["esp_mqtt_client_init()", "esp_mqtt_client_subscribe()", "esp_mqtt_client_publish()"] },
]
},
{
category: "WebSocket",
items: [
{ name: "esp_websocket_client", description: "WebSocket client", apis: ["esp_websocket_client_init()", "esp_websocket_client_send_text()"] },
]
},
{
category: "mDNS/DNS",
items: [
{ name: "mdns", description: "Multicast DNS service discovery", apis: ["mdns_init()", "mdns_hostname_set()", "mdns_service_add()"] },
]
},
{
category: "TLS/SSL",
items: [
{ name: "esp_tls", description: "TLS/SSL wrapper (mbedTLS 3.6.0)", apis: ["esp_tls_conn_new()", "esp_tls_conn_read()", "esp_tls_conn_write()"] },
{ name: "esp_crt_bundle", description: "Certificate bundle for HTTPS", apis: ["esp_crt_bundle_attach()"] },
]
},
];
const storageOptions = [
{
name: "NVS (Non-Volatile Storage)",
icon: Database,
description: "Key-value storage for configuration and small data",
apis: ["nvs_flash_init()", "nvs_open()", "nvs_set_str()", "nvs_get_i32()", "nvs_commit()"],
useCase: "WiFi credentials, device settings, calibration data"
},
{
name: "SPIFFS",
icon: HardDrive,
description: "SPI Flash File System for read-heavy workloads",
apis: ["esp_vfs_spiffs_register()", "fopen()", "fread()", "fwrite()"],
useCase: "Web assets, configuration files, logs"
},
{
name: "FATFS",
icon: HardDrive,
description: "FAT file system with SD card support",
apis: ["esp_vfs_fat_mount()", "esp_vfs_fat_sdmmc_mount()"],
useCase: "SD card data logging, removable storage"
},
{
name: "LittleFS",
icon: HardDrive,
description: "Power-loss resilient file system",
apis: ["esp_vfs_littlefs_register()"],
useCase: "Frequent writes, power-unstable environments"
},
{
name: "Wear Leveling",
icon: RefreshCw,
description: "Flash wear leveling layer",
apis: ["wl_mount()", "wl_read()", "wl_write()"],
useCase: "Extend flash lifespan for heavy write workloads"
},
];
const securityFeatures = [
{
name: "Secure Boot V2",
icon: Shield,
description: "Cryptographic verification of boot chain",
details: ["RSA-3072 or ECDSA signatures", "Anti-rollback protection", "Hardware root of trust"]
},
{
name: "Flash Encryption",
icon: Lock,
description: "AES-256 encryption of flash contents",
details: ["Hardware encryption engine", "Transparent to application", "Development & Release modes"]
},
{
name: "Hardware Crypto",
icon: Cpu,
description: "Hardware-accelerated cryptographic operations",
details: ["AES, SHA, RSA, ECDSA", "Random number generator", "Digital signature peripheral"]
},
{
name: "mbedTLS 3.6.0",
icon: Lock,
description: "TLS/SSL library (updated in v5.4)",
details: ["TLS 1.2/1.3 support", "Certificate management", "Optimized RAM usage (v5.4)"]
},
];
const v54Highlights = [
{ title: "ESP32-P4 Support", description: "Initial support for the high-performance non-wireless SoC with dual RISC-V cores" },
{ title: "Sleep Retention", description: "GPIO, SPI, I2C peripherals maintain state during light sleep on C6/H2" },
{ title: "PSRAM Retention", description: "External PSRAM data preserved during light sleep on supported chips" },
{ title: "mbedTLS 3.6.0", description: "Updated TLS library with reduced RAM usage for Certificate Bundle" },
{ title: "LP Core Expansion", description: "LP-ADC, LP-SPI, LP-I2C support on C6/P4 for ultra-low power operation" },
{ title: "NimBLE 1.7.0", description: "Updated BLE stack with improved stability and features" },
{ title: "WiFi FTM", description: "Fine Timing Measurement calibration support for C6" },
{ title: "Thread TREL", description: "Thread Radio Encapsulation Link support for improved mesh networking" },
{ title: "Bootloader Mocks", description: "New mocking framework for improved unit testing capabilities" },
{ title: "AVRCP Cover Art", description: "Bluedroid now supports album artwork transfer over Bluetooth" },
];
const ESPIDFHelperPage = () => {
const [searchTerm, setSearchTerm] = useState("");
const filteredPeripherals = peripherals.filter(p =>
p.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
p.description.toLowerCase().includes(searchTerm.toLowerCase())
);
return (
<AppLayout>
<div className="p-6 space-y-6">
{/* Header */}
<div className="flex flex-col md:flex-row md:items-center justify-between gap-4">
<div>
<div className="flex items-center gap-3">
<div className="p-2 bg-primary/10 rounded-lg">
<Cpu className="h-8 w-8 text-primary" />
</div>
<div>
<h1 className="text-3xl font-bold text-foreground">ESP-IDF V5.4 Helper</h1>
<p className="text-muted-foreground">Comprehensive reference for Espressif IoT Development Framework</p>
</div>
</div>
</div>
<div className="flex items-center gap-2">
<Badge variant="outline" className="text-sm">
Version 5.4.3 (Latest)
</Badge>
<a
href="https://github.com/espressif/esp-idf/tree/release/v5.4"
target="_blank"
rel="noopener noreferrer"
className="inline-flex items-center gap-1 text-sm text-primary hover:underline"
>
GitHub <ExternalLink className="h-3 w-3" />
</a>
<a
href="https://docs.espressif.com/projects/esp-idf/en/v5.4/"
target="_blank"
rel="noopener noreferrer"
className="inline-flex items-center gap-1 text-sm text-primary hover:underline"
>
Docs <ExternalLink className="h-3 w-3" />
</a>
</div>
</div>
{/* V5.4 Highlights */}
<Card className="border-primary/20 bg-primary/5">
<CardHeader className="pb-3">
<CardTitle className="flex items-center gap-2 text-lg">
<Zap className="h-5 w-5 text-primary" />
What's New in ESP-IDF V5.4
</CardTitle>
</CardHeader>
<CardContent>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-5 gap-3">
{v54Highlights.map((item, idx) => (
<div key={idx} className="p-3 bg-background rounded-lg border">
<p className="font-medium text-sm text-foreground">{item.title}</p>
<p className="text-xs text-muted-foreground mt-1">{item.description}</p>
</div>
))}
</div>
</CardContent>
</Card>
{/* Search */}
<div className="relative max-w-md">
<Search className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" />
<Input
placeholder="Search peripherals, APIs, features..."
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
className="pl-10"
/>
</div>
<Tabs defaultValue="chips" className="space-y-4">
<TabsList className="flex-wrap h-auto gap-1">
<TabsTrigger value="chips">Supported Chips</TabsTrigger>
<TabsTrigger value="peripherals">Peripherals</TabsTrigger>
<TabsTrigger value="networking">Networking</TabsTrigger>
<TabsTrigger value="protocols">Protocols & Libraries</TabsTrigger>
<TabsTrigger value="storage">Storage</TabsTrigger>
<TabsTrigger value="security">Security</TabsTrigger>
<TabsTrigger value="tools">Development Tools</TabsTrigger>
</TabsList>
{/* Supported Chips */}
<TabsContent value="chips" className="space-y-4">
<Card>
<CardHeader>
<CardTitle>Supported Microcontrollers</CardTitle>
<CardDescription>ESP-IDF V5.4 supports the following ESP32 series chips</CardDescription>
</CardHeader>
<CardContent>
<div className="overflow-x-auto">
<table className="w-full text-sm">
<thead>
<tr className="border-b">
<th className="text-left p-3 font-medium">Chip</th>
<th className="text-left p-3 font-medium">Processor</th>
<th className="text-left p-3 font-medium">Flash</th>
<th className="text-left p-3 font-medium">RAM</th>
<th className="text-left p-3 font-medium">WiFi</th>
<th className="text-left p-3 font-medium">Bluetooth</th>
<th className="text-left p-3 font-medium">Status</th>
</tr>
</thead>
<tbody>
{supportedChips.map((chip) => (
<tr key={chip.name} className="border-b hover:bg-muted/50">
<td className="p-3 font-medium">{chip.name}</td>
<td className="p-3 text-muted-foreground">{chip.cores}</td>
<td className="p-3 text-muted-foreground">{chip.flash}</td>
<td className="p-3 text-muted-foreground">{chip.ram}</td>
<td className="p-3">
{chip.wifi ? (
<Badge variant="outline" className="bg-green-500/10 text-green-600 border-green-500/20">
{typeof chip.wifi === 'string' ? chip.wifi : 'Yes'}
</Badge>
) : (
<Badge variant="outline" className="bg-muted text-muted-foreground">No</Badge>
)}
</td>
<td className="p-3">
{chip.bt ? (
<Badge variant="outline" className="bg-blue-500/10 text-blue-600 border-blue-500/20">
{chip.bt}
</Badge>
) : (
<Badge variant="outline" className="bg-muted text-muted-foreground">No</Badge>
)}
</td>
<td className="p-3">
<Badge variant={chip.status === "Stable" ? "default" : "secondary"}>
{chip.status}
</Badge>
</td>
</tr>
))}
</tbody>
</table>
</div>
</CardContent>
</Card>
</TabsContent>
{/* Peripherals */}
<TabsContent value="peripherals" className="space-y-4">
<div className="grid grid-cols-1 lg:grid-cols-2 gap-4">
{filteredPeripherals.map((peripheral) => (
<Card key={peripheral.name}>
<CardHeader className="pb-3">
<CardTitle className="flex items-center gap-2 text-lg">
<peripheral.icon className="h-5 w-5 text-primary" />
{peripheral.name}
</CardTitle>
<CardDescription>{peripheral.description}</CardDescription>
</CardHeader>
<CardContent className="space-y-3">
<div>
<p className="text-xs font-medium text-muted-foreground mb-2">KEY APIs</p>
<div className="flex flex-wrap gap-1">
{peripheral.apis.map((api) => (
<code key={api} className="px-2 py-0.5 bg-muted rounded text-xs font-mono">
{api}
</code>
))}
</div>
</div>
<div>
<p className="text-xs font-medium text-muted-foreground mb-2">FEATURES</p>
<ul className="text-sm text-muted-foreground space-y-1">
{peripheral.features.map((feature) => (
<li key={feature} className="flex items-center gap-2">
<div className="h-1.5 w-1.5 rounded-full bg-primary" />
{feature}
</li>
))}
</ul>
</div>
</CardContent>
</Card>
))}
</div>
</TabsContent>
{/* Networking */}
<TabsContent value="networking" className="space-y-4">
<div className="grid grid-cols-1 lg:grid-cols-2 gap-4">
{networkingFeatures.map((feature) => (
<Card key={feature.name}>
<CardHeader className="pb-3">
<CardTitle className="flex items-center gap-2 text-lg">
<feature.icon className="h-5 w-5 text-primary" />
{feature.name}
</CardTitle>
<CardDescription>{feature.description}</CardDescription>
</CardHeader>
<CardContent className="space-y-3">
<div>
<p className="text-xs font-medium text-muted-foreground mb-2">MODES</p>
<div className="flex flex-wrap gap-1">
{feature.modes.map((mode) => (
<Badge key={mode} variant="outline" className="text-xs">
{mode}
</Badge>
))}
</div>
</div>
<div>
<p className="text-xs font-medium text-muted-foreground mb-2">KEY APIs</p>
<div className="flex flex-wrap gap-1">
{feature.apis.map((api) => (
<code key={api} className="px-2 py-0.5 bg-muted rounded text-xs font-mono">
{api}
</code>
))}
</div>
</div>
<div>
<p className="text-xs font-medium text-muted-foreground mb-2">FEATURES</p>
<ul className="text-sm text-muted-foreground space-y-1">
{feature.features.map((f) => (
<li key={f} className="flex items-center gap-2">
<div className="h-1.5 w-1.5 rounded-full bg-primary" />
{f}
</li>
))}
</ul>
</div>
</CardContent>
</Card>
))}
</div>
</TabsContent>
{/* Protocols & Libraries */}
<TabsContent value="protocols" className="space-y-4">
{protocolsLibraries.map((category) => (
<Card key={category.category}>
<CardHeader className="pb-3">
<CardTitle className="text-lg">{category.category}</CardTitle>
</CardHeader>
<CardContent>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
{category.items.map((item) => (
<div key={item.name} className="p-3 bg-muted/50 rounded-lg">
<p className="font-medium text-sm">{item.name}</p>
<p className="text-xs text-muted-foreground mt-1">{item.description}</p>
<div className="flex flex-wrap gap-1 mt-2">
{item.apis.map((api) => (
<code key={api} className="px-1.5 py-0.5 bg-background rounded text-xs font-mono">
{api}
</code>
))}
</div>
</div>
))}
</div>
</CardContent>
</Card>
))}
</TabsContent>
{/* Storage */}
<TabsContent value="storage" className="space-y-4">
<div className="grid grid-cols-1 lg:grid-cols-2 xl:grid-cols-3 gap-4">
{storageOptions.map((storage) => (
<Card key={storage.name}>
<CardHeader className="pb-3">
<CardTitle className="flex items-center gap-2 text-lg">
<storage.icon className="h-5 w-5 text-primary" />
{storage.name}
</CardTitle>
<CardDescription>{storage.description}</CardDescription>
</CardHeader>
<CardContent className="space-y-3">
<div>
<p className="text-xs font-medium text-muted-foreground mb-2">KEY APIs</p>
<div className="flex flex-wrap gap-1">
{storage.apis.map((api) => (
<code key={api} className="px-2 py-0.5 bg-muted rounded text-xs font-mono">
{api}
</code>
))}
</div>
</div>
<div className="p-2 bg-muted/50 rounded">
<p className="text-xs font-medium text-muted-foreground">USE CASE</p>
<p className="text-sm mt-1">{storage.useCase}</p>
</div>
</CardContent>
</Card>
))}
</div>
</TabsContent>
{/* Security */}
<TabsContent value="security" className="space-y-4">
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
{securityFeatures.map((feature) => (
<Card key={feature.name}>
<CardHeader className="pb-3">
<CardTitle className="flex items-center gap-2 text-lg">
<feature.icon className="h-5 w-5 text-primary" />
{feature.name}
</CardTitle>
<CardDescription>{feature.description}</CardDescription>
</CardHeader>
<CardContent>
<ul className="space-y-2">
{feature.details.map((detail) => (
<li key={detail} className="flex items-center gap-2 text-sm">
<div className="h-1.5 w-1.5 rounded-full bg-green-500" />
{detail}
</li>
))}
</ul>
</CardContent>
</Card>
))}
</div>
</TabsContent>
{/* Development Tools */}
<TabsContent value="tools" className="space-y-4">
<div className="grid grid-cols-1 lg:grid-cols-2 gap-4">
<Card>
<CardHeader>
<CardTitle className="flex items-center gap-2">
<Terminal className="h-5 w-5 text-primary" />
idf.py - Build System
</CardTitle>
<CardDescription>Primary command-line tool for ESP-IDF projects</CardDescription>
</CardHeader>
<CardContent className="space-y-3">
<div className="space-y-2">
<div className="p-2 bg-muted rounded font-mono text-sm">
<span className="text-muted-foreground">$</span> idf.py set-target esp32s3
</div>
<div className="p-2 bg-muted rounded font-mono text-sm">
<span className="text-muted-foreground">$</span> idf.py menuconfig
</div>
<div className="p-2 bg-muted rounded font-mono text-sm">
<span className="text-muted-foreground">$</span> idf.py build
</div>
<div className="p-2 bg-muted rounded font-mono text-sm">
<span className="text-muted-foreground">$</span> idf.py -p /dev/ttyUSB0 flash monitor
</div>
</div>
</CardContent>
</Card>
<Card>
<CardHeader>
<CardTitle className="flex items-center gap-2">
<Settings className="h-5 w-5 text-primary" />
menuconfig - Configuration
</CardTitle>
<CardDescription>Interactive configuration system for project settings</CardDescription>
</CardHeader>
<CardContent>
<ul className="space-y-2 text-sm">
<li className="flex items-center gap-2">
<div className="h-1.5 w-1.5 rounded-full bg-primary" />
Component configuration (WiFi, Bluetooth, etc.)
</li>
<li className="flex items-center gap-2">
<div className="h-1.5 w-1.5 rounded-full bg-primary" />
Compiler and optimization settings
</li>
<li className="flex items-center gap-2">
<div className="h-1.5 w-1.5 rounded-full bg-primary" />
Partition table configuration
</li>
<li className="flex items-center gap-2">
<div className="h-1.5 w-1.5 rounded-full bg-primary" />
Security settings (Secure Boot, Flash Encryption)
</li>
<li className="flex items-center gap-2">
<div className="h-1.5 w-1.5 rounded-full bg-primary" />
FreeRTOS and system configuration
</li>
</ul>
</CardContent>
</Card>
<Card>
<CardHeader>
<CardTitle className="flex items-center gap-2">
<Monitor className="h-5 w-5 text-primary" />
Debugging Tools
</CardTitle>
<CardDescription>Tools for debugging and profiling</CardDescription>
</CardHeader>
<CardContent>
<ul className="space-y-2 text-sm">
<li className="flex items-center gap-2">
<div className="h-1.5 w-1.5 rounded-full bg-primary" />
<strong>idf.py monitor</strong> - Serial console output
</li>
<li className="flex items-center gap-2">
<div className="h-1.5 w-1.5 rounded-full bg-primary" />
<strong>GDB</strong> - Hardware debugging via JTAG
</li>
<li className="flex items-center gap-2">
<div className="h-1.5 w-1.5 rounded-full bg-primary" />
<strong>Core Dump</strong> - Post-mortem analysis
</li>
<li className="flex items-center gap-2">
<div className="h-1.5 w-1.5 rounded-full bg-primary" />
<strong>Application Tracing</strong> - Real-time tracing
</li>
<li className="flex items-center gap-2">
<div className="h-1.5 w-1.5 rounded-full bg-primary" />
<strong>Heap Analysis</strong> - Memory debugging
</li>
</ul>
</CardContent>
</Card>
<Card>
<CardHeader>
<CardTitle className="flex items-center gap-2">
<Code className="h-5 w-5 text-primary" />
FreeRTOS APIs
</CardTitle>
<CardDescription>Real-time operating system primitives</CardDescription>
</CardHeader>
<CardContent className="space-y-3">
<div>
<p className="text-xs font-medium text-muted-foreground mb-2">TASK MANAGEMENT</p>
<div className="flex flex-wrap gap-1">
{["xTaskCreate()", "vTaskDelete()", "vTaskDelay()", "xTaskNotify()"].map((api) => (
<code key={api} className="px-2 py-0.5 bg-muted rounded text-xs font-mono">
{api}
</code>
))}
</div>
</div>
<div>
<p className="text-xs font-medium text-muted-foreground mb-2">SYNCHRONIZATION</p>
<div className="flex flex-wrap gap-1">
{["xSemaphoreCreateMutex()", "xQueueCreate()", "xEventGroupCreate()"].map((api) => (
<code key={api} className="px-2 py-0.5 bg-muted rounded text-xs font-mono">
{api}
</code>
))}
</div>
</div>
<div>
<p className="text-xs font-medium text-muted-foreground mb-2">ESP EVENT LOOP</p>
<div className="flex flex-wrap gap-1">
{["esp_event_loop_create_default()", "esp_event_handler_register()", "esp_event_post()"].map((api) => (
<code key={api} className="px-2 py-0.5 bg-muted rounded text-xs font-mono">
{api}
</code>
))}
</div>
</div>
</CardContent>
</Card>
</div>
</TabsContent>
</Tabs>
</div>
</AppLayout>
);
};
export default ESPIDFHelperPage;