Skip to content

Commit

Permalink
feat: introduce new components and update docs
Browse files Browse the repository at this point in the history
  • Loading branch information
drewstone committed Oct 30, 2024
1 parent 1597880 commit f12c862
Show file tree
Hide file tree
Showing 217 changed files with 1,862 additions and 1,503 deletions.
58 changes: 38 additions & 20 deletions components/BlueprintIntroCards.tsx
Original file line number Diff line number Diff line change
@@ -1,47 +1,65 @@
import React from "react";
import { GrNodes } from "react-icons/gr";
import { BetweenVerticalEnd } from "lucide-react";
import Link from "next/link";
import { FaChevronRight } from "react-icons/fa";

const BlueprintIntroCards = () => {
const cards = [
{
icon: <BetweenVerticalEnd className="text-blue-500" size={24} />,
title: "Tangle's Gadget SDK Repo",
title: "Tangle's Blueprint Gadget SDK",
description:
"Check out our Gadget SDK repository to get started building your own gadgets.",
link: "https://github.com/tangle-network/gadget",
"Learn about the Gadget SDK and how to get started building your own gadgets.",
link: "/developers/gadget-sdk",
},
{
icon: <BetweenVerticalEnd className="text-blue-500" size={24} />,
title: "Hello World Blueprint",
description:
"Get started with a simple Hello World example using Tangle Blueprints.",
link: "../developers/getting-started",
link: "/developers/tangle-avs",
},
{
icon: <GrNodes className="text-blue-500" size={24} />,
title: "Build an Eigenlayer AVS",
description:
"Build an Eigenlayer AVS with the Tangle Blueprint SDK and hook into a variety of EVM compatible utilities for task automation, slashing, and more.",
link: "../developers/eigenlayer-avs",
link: "/developers/eigenlayer-avs",
},
];

return (
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-8 my-12">
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4 my-6">
{cards.map((card, index) => (
<Link href={card.link} key={index} className="block">
<div className="border border-black dark:border-white p-4 h-full flex flex-col transition-colors duration-300 hover:bg-purple-100 dark:hover:bg-purple-900">
<div className="flex-shrink-0 mb-2">{card.icon}</div>
<h3 className="text-xl font-bold mb-4 text-black dark:text-white">
{card.title}
</h3>
<p className="text-sm flex-grow text-black dark:text-white">
<div
key={index}
className="relative p-5 border border-gray-200 dark:border-gray-800 rounded-lg
hover:border-purple-500 dark:hover:border-purple-400
transition-all duration-200 hover:shadow-lg
bg-gradient-to-br from-white to-gray-50
dark:from-gray-900 dark:to-gray-800"
>
<Link href={card.link} className="group block">
<div className="flex justify-between items-start mb-3">
<h3
className="text-lg font-semibold text-gray-900 dark:text-gray-100
group-hover:text-purple-600 dark:group-hover:text-purple-400
transition-colors duration-200"
>
{card.title}
</h3>
<FaChevronRight
className="text-gray-400 group-hover:text-purple-500
transform group-hover:translate-x-1 transition-all"
/>
</div>
<p className="text-sm text-gray-600 dark:text-gray-400">
{card.description}
</p>
</div>
</Link>
</Link>

<div
className="absolute inset-0 rounded-lg bg-purple-500/[0.03]
opacity-0 group-hover:opacity-100 transition-opacity
pointer-events-none"
/>
</div>
))}
</div>
);
Expand Down
182 changes: 182 additions & 0 deletions components/GithubFileReaderDisplay.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
import React, { useEffect, useState } from "react";
import { FaGithub, FaLink, FaSpinner } from "react-icons/fa";
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
import {
nightOwl,
oneLight,
} from "react-syntax-highlighter/dist/cjs/styles/prism";
import { useTheme } from "next-themes";

let lightTheme = oneLight;
let darkTheme = nightOwl;

interface GithubFileReaderDisplayProps {
url: string;
fromLine?: number;
toLine?: number;
title?: string;
}

const GithubFileReaderDisplay: React.FC<GithubFileReaderDisplayProps> = ({
url,
fromLine = 1,
toLine,
title,
}) => {
const [content, setContent] = useState<string>("");
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
const { theme } = useTheme();

const getLanguage = (url: string) => {
const extension = url.split(".").pop()?.toLowerCase();
switch (extension) {
case "rs":
return "rust";
case "ts":
case "tsx":
return "typescript";
case "js":
case "jsx":
return "javascript";
case "sol":
return "solidity";
case "md":
case "mdx":
return "markdown";
case "toml":
return "toml";
case "yaml":
case "yml":
return "yaml";
case "json":
return "json";
case "sh":
return "bash";
case "py":
return "python";
case "go":
return "go";
case "cpp":
case "c++":
case "cc":
return "cpp";
case "c":
return "c";
case "java":
return "java";
case "php":
return "php";
case "rb":
return "ruby";
case "swift":
return "swift";
case "kt":
return "kotlin";
case "cs":
return "csharp";
case "html":
return "html";
case "css":
return "css";
case "scss":
return "scss";
case "sql":
return "sql";
case "graphql":
case "gql":
return "graphql";
default:
return "text";
}
};

useEffect(() => {
const fetchGithubContent = async () => {
try {
const rawUrl = url
.replace("github.com", "raw.githubusercontent.com")
.replace("/blob/", "/");

const response = await fetch(rawUrl);
if (!response.ok) {
throw new Error("Failed to fetch file content");
}

const text = await response.text();
const lines = text.split("\n");
const selectedLines = lines.slice(fromLine - 1, toLine || lines.length);
setContent(selectedLines.join("\n"));
setLoading(false);
} catch (err) {
setError(err instanceof Error ? err.message : "An error occurred");
setLoading(false);
}
};

fetchGithubContent();
}, [url, fromLine, toLine]);

if (loading) {
return (
<div className="flex items-center justify-center p-8 border border-gray-200 dark:border-gray-800 rounded-lg">
<FaSpinner className="animate-spin text-purple-500 text-2xl" />
</div>
);
}

if (error) {
return (
<div className="p-4 border border-red-200 dark:border-red-800 bg-red-50 dark:bg-red-900/20 rounded-lg text-red-600 dark:text-red-400">
Error: {error}
</div>
);
}

return (
<div className="my-6 overflow-hidden border border-gray-200 dark:border-gray-800 rounded-lg">
<div className="flex justify-between items-center px-4 py-2 bg-gray-50 dark:bg-gray-800/50 border-b border-gray-200 dark:border-gray-800">
<div className="flex items-center space-x-2">
<FaGithub className="text-gray-600 dark:text-gray-400" />
<span className="text-sm font-medium text-gray-700 dark:text-gray-300">
{title || url.split("/").slice(-1)[0]}
</span>
</div>
<div className="flex items-center space-x-2">
<span className="text-xs text-gray-500 dark:text-gray-400">
Lines {fromLine}-{toLine || "end"}
</span>
<a
href={url}
target="_blank"
rel="noopener noreferrer"
className="p-1.5 rounded-md hover:bg-gray-100 dark:hover:bg-gray-700 text-gray-600 dark:text-gray-400 transition-colors duration-200"
aria-label="View on GitHub"
>
<FaLink className="text-sm" />
</a>
</div>
</div>

<SyntaxHighlighter
language={getLanguage(url)}
style={theme === "light" ? lightTheme : darkTheme}
customStyle={{
margin: 0,
padding: "1rem",
background: "transparent",
fontSize: "0.875rem",
lineHeight: "1.5",
}}
showLineNumbers
startingLineNumber={fromLine}
wrapLines
wrapLongLines
>
{content}
</SyntaxHighlighter>
</div>
);
};

export default GithubFileReaderDisplay;
Loading

0 comments on commit f12c862

Please sign in to comment.