[dyad] Added system detection tab - wrote 4 file(s)

This commit is contained in:
[dyad]
2026-01-21 07:53:01 +01:00
parent d742339c1d
commit 8c68562830
4 changed files with 188 additions and 7 deletions

View File

@@ -28,6 +28,10 @@ export interface LinkData {
rel: string; rel: string;
} }
export interface DetectedSystem {
name: string;
}
export async function extractMetaData(url: string, keyword?: string) { export async function extractMetaData(url: string, keyword?: string) {
if (!url) { if (!url) {
return { error: "URL is required." }; return { error: "URL is required." };
@@ -225,6 +229,60 @@ export async function extractMetaData(url: string, keyword?: string) {
links.push({ href: absoluteUrl, text, type, rel }); links.push({ href: absoluteUrl, text, type, rel });
}); });
const detectedSystems: DetectedSystem[] = [];
const htmlContent = $.html();
const uniqueSystems = new Set<string>();
// WordPress
if (
$('meta[name="generator"][content*="WordPress"]').length > 0 ||
htmlContent.includes("/wp-content/") ||
htmlContent.includes("/wp-includes/")
) {
uniqueSystems.add("WordPress");
}
// Shopify
if (
htmlContent.includes("cdn.shopify.com") ||
htmlContent.includes("Shopify.theme")
) {
uniqueSystems.add("Shopify");
}
// Next.js
if ($("#__next").length > 0) {
uniqueSystems.add("Next.js");
uniqueSystems.add("React"); // Next.js uses React
}
// React (generic)
if ($("#root").length > 0) {
uniqueSystems.add("React");
}
// Webflow
if (
$('meta[name="generator"][content="Webflow"]').length > 0 ||
htmlContent.includes("<!-- This site was created in Webflow.")
) {
uniqueSystems.add("Webflow");
}
// Wix
if ($('meta[name="generator"][content*="Wix.com"]').length > 0) {
uniqueSystems.add("Wix");
}
// Squarespace
if (htmlContent.includes("static1.squarespace.com")) {
uniqueSystems.add("Squarespace");
}
uniqueSystems.forEach((system) => {
detectedSystems.push({ name: system });
});
return { return {
data: { data: {
title, title,
@@ -241,6 +299,7 @@ export async function extractMetaData(url: string, keyword?: string) {
keywordCount, keywordCount,
images: imageAltData.length > 0 ? imageAltData : null, images: imageAltData.length > 0 ? imageAltData : null,
links: links.length > 0 ? links : null, links: links.length > 0 ? links : null,
systems: detectedSystems.length > 0 ? detectedSystems : null,
}, },
}; };
} catch (error) { } catch (error) {

View File

@@ -15,6 +15,7 @@ import { MetaFormInputs } from "./meta-form-inputs";
import { AnalysisTab } from "./analysis-tab"; import { AnalysisTab } from "./analysis-tab";
import { SocialTab } from "./social-tab"; import { SocialTab } from "./social-tab";
import { LinksDisplay } from "./links-display"; import { LinksDisplay } from "./links-display";
import { SystemDisplay } from "./system-display";
import type { MetaData } from "@/lib/types"; import type { MetaData } from "@/lib/types";
export function MetaForm() { export function MetaForm() {
@@ -125,6 +126,10 @@ export function MetaForm() {
schemaColor = "green"; schemaColor = "green";
} }
// System Tab
const systemColor: IndicatorColor =
metaData.systems && metaData.systems.length > 0 ? "green" : "gray";
return { return {
analysis: analysisColor, analysis: analysisColor,
headlines: headlinesColor, headlines: headlinesColor,
@@ -133,6 +138,7 @@ export function MetaForm() {
links: linksColor, links: linksColor,
faq: faqColor, faq: faqColor,
schema: schemaColor, schema: schemaColor,
system: systemColor,
}; };
}, [metaData, editableTitle, editableDescription]); }, [metaData, editableTitle, editableDescription]);
@@ -218,18 +224,24 @@ export function MetaForm() {
Social Social
</TabsTrigger> </TabsTrigger>
)} )}
{metaData.faq && metaData.faq.length > 0 && (
<TabsTrigger value="faq">
{tabColors && <TabIndicator color={tabColors.faq} />}
FAQ
</TabsTrigger>
)}
{metaData.schema && metaData.schema.length > 0 && ( {metaData.schema && metaData.schema.length > 0 && (
<TabsTrigger value="schema"> <TabsTrigger value="schema">
{tabColors && <TabIndicator color={tabColors.schema} />} {tabColors && <TabIndicator color={tabColors.schema} />}
Schema Schema
</TabsTrigger> </TabsTrigger>
)} )}
{metaData.systems && metaData.systems.length > 0 && (
<TabsTrigger value="system">
{tabColors && <TabIndicator color={tabColors.system} />}
System
</TabsTrigger>
)}
{metaData.faq && metaData.faq.length > 0 && (
<TabsTrigger value="faq">
{tabColors && <TabIndicator color={tabColors.faq} />}
FAQ
</TabsTrigger>
)}
</TabsList> </TabsList>
<TabsContent value="analysis"> <TabsContent value="analysis">
@@ -313,6 +325,12 @@ export function MetaForm() {
</Card> </Card>
</TabsContent> </TabsContent>
)} )}
{metaData.systems && metaData.systems.length > 0 && (
<TabsContent value="system">
<SystemDisplay systems={metaData.systems} />
</TabsContent>
)}
</Tabs> </Tabs>
)} )}
</div> </div>

View File

@@ -0,0 +1,98 @@
"use client";
import type { DetectedSystem } from "@/app/actions";
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import {
Code,
Server,
ShoppingCart,
Square,
PenTool,
} from "lucide-react";
interface SystemDisplayProps {
systems: DetectedSystem[];
}
const systemInfo: {
[key: string]: { icon: React.ElementType; description: string };
} = {
WordPress: {
icon: Code,
description: "A popular open-source content management system.",
},
Shopify: {
icon: ShoppingCart,
description: "An e-commerce platform for online stores.",
},
"Next.js": {
icon: Server,
description: "A React framework for building full-stack web applications.",
},
React: {
icon: Code,
description: "A JavaScript library for building user interfaces.",
},
Webflow: {
icon: PenTool,
description: "A visual web development platform.",
},
Wix: { icon: Square, description: "A cloud-based web development platform." },
Squarespace: {
icon: Square,
description: "A website builder and hosting service.",
},
Default: {
icon: Code,
description: "A detected web technology or framework.",
},
};
export function SystemDisplay({ systems }: SystemDisplayProps) {
return (
<Card className="w-full shadow-lg rounded-lg">
<CardHeader>
<CardTitle>System Analysis</CardTitle>
<CardDescription>
Technologies and frameworks detected on the page.
</CardDescription>
</CardHeader>
<CardContent>
{systems && systems.length > 0 ? (
<div className="space-y-4">
{systems.map((system, index) => {
const info = systemInfo[system.name] || systemInfo["Default"];
const Icon = info.icon;
return (
<div
key={index}
className="flex items-start gap-4 p-4 border rounded-lg bg-muted/50"
>
<div className="flex h-10 w-10 flex-shrink-0 items-center justify-center rounded-lg bg-primary text-primary-foreground">
<Icon className="h-6 w-6" />
</div>
<div>
<h4 className="font-semibold text-lg">{system.name}</h4>
<p className="text-sm text-muted-foreground">
{info.description}
</p>
</div>
</div>
);
})}
</div>
) : (
<div className="text-center py-8 text-muted-foreground">
<p>No specific frameworks or CMS detected.</p>
</div>
)}
</CardContent>
</Card>
);
}

View File

@@ -1,4 +1,9 @@
import type { HeadlineNode, ImageAltData, LinkData } from "@/app/actions"; import type {
HeadlineNode,
ImageAltData,
LinkData,
DetectedSystem,
} from "@/app/actions";
export interface OpenGraphData { export interface OpenGraphData {
title: string; title: string;
@@ -33,4 +38,5 @@ export interface MetaData {
openGraph?: OpenGraphData; openGraph?: OpenGraphData;
twitter?: TwitterData; twitter?: TwitterData;
links?: LinkData[] | null; links?: LinkData[] | null;
systems?: DetectedSystem[] | null;
} }