Skip to content

Commit

Permalink
Merge pull request #95 from partyparrotgreg/feat/ecosystem-map
Browse files Browse the repository at this point in the history
feat: ecosystem map components and data
  • Loading branch information
codebycarson authored Jul 3, 2024
2 parents f63eba8 + bbe9805 commit 3b0b34d
Show file tree
Hide file tree
Showing 12 changed files with 335 additions and 350 deletions.
3 changes: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,5 +51,6 @@
"nextjs-intellisense.includePaths": [
"./src",
"./pages"
]
],
"npm-scripts.showStartNotification": false
}
41 changes: 41 additions & 0 deletions components/EcosystemMap/EcosystemDynamicSection.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { useEffect, useState } from 'react'
import { EcosystemSection, EcosystemSkeleton } from '.'
import {
EcosystemResponse,
getSeiEcosystemAppsData,
} from '../../data/ecosystemData'

const EcosystemDynamicSection = ({ category }: { category: string }) => {
const [apps, setApps] = useState<EcosystemResponse['data'] | null>(null)
const [loading, setLoading] = useState(true)

useEffect(() => {
const fetchData = async () => {
await getSeiEcosystemAppsData()
.then((data) => {
setApps(data.data)
setLoading(false)
})
.catch((error) => {
console.error('Failed to fetch data:', error)
})
.finally(() => {
setLoading(false)
})
}
fetchData()
}, [])

if (!apps || loading) return <EcosystemSkeleton />

// filter out apps that don't have a categorie
const filteredApps = apps.filter(
(app) => app.fieldData.categorie !== undefined
)

const appsByCategory = (category: string) =>
filteredApps.filter((app) => app.fieldData.categorie === category)
return <EcosystemSection apps={appsByCategory(category)} />
}

export default EcosystemDynamicSection
103 changes: 103 additions & 0 deletions components/EcosystemMap/EcosystemMap.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import { useConfig } from 'nextra-theme-docs'
import { useEffect, useState } from 'react'
import { groupBy } from 'underscore'
import { EcosystemSection, EcosystemSkeleton } from '.'
import {
EcosystemResponse,
getSeiEcosystemAppsData,
} from '../../data/ecosystemData'

// ;[
// 'Consumer Apps',
// 'Infrastructure',
// 'DeFi',
// 'Data & Analytics',
// 'Wallets',
// 'NFTs',
// 'Exchanges & On/Off Ramps',
// 'Other',
// 'AI',
// ]


const EcosystemMap = () => {
const [apps, setApps] = useState<EcosystemResponse['data'] | null>(null)
const [loading, setLoading] = useState(true)

const config = useConfig()

console.log(config)
useEffect(() => {
const fetchData = async () => {
await getSeiEcosystemAppsData()
.then((data) => {
setApps(data.data)
setLoading(false)
})
.catch((error) => {
console.error('Failed to fetch data:', error)
})
.finally(() => {
setLoading(false)
})
}
fetchData()
}, [])

if (!apps || loading) return <EcosystemSkeleton />

// filter out apps that don't have a categorie
const filteredApps = apps.filter(
(app) => app.fieldData.categorie !== undefined
)

// group apps by category
const groupAppsByCategory = groupBy(
filteredApps,
(app) => app.fieldData.categorie
)

const categories = Object.keys(groupAppsByCategory)
console.log(categories)
const mappedCategories = categories.map((category) => {
if (category === undefined) return
return {
label: category,
// replace spaces with hyphens and remove special characters like & and / from the category name
value: category
.replace(/\s/g, '-')
.replace(/[&/\s]/g, '')
.toLowerCase()
.replace(/-+/g, '-'),
}
})

const appsByCategory = (category: string) =>
apps.filter((app) => app.fieldData.categorie === category)

return (
<div className="mt-8">
<div className="flex flex-col gap-8 mt-8">
{mappedCategories.map(({ label, value }) => {
return (
<div key={value} className="flex flex-col gap-4 ">
{/* <h2 className="text-2xl font-semibold">{label}</h2> */}
<h2 className="nx-font-semibold nx-tracking-tight nx-text-slate-900 dark:nx-text-slate-100 nx-mt-10 nx-border-b nx-pb-1 nx-text-3xl nx-border-neutral-200/70 contrast-more:nx-border-neutral-400 dark:nx-border-primary-100/10 contrast-more:dark:nx-border-neutral-400">
{label}
<a
href={`#${value}`}
id="overview"
className="subheading-anchor"
aria-label="Permalink for this section"
></a>
</h2>
<EcosystemSection apps={appsByCategory(label)} />
</div>
)
})}
</div>
</div>
)
}

export default EcosystemMap
37 changes: 37 additions & 0 deletions components/EcosystemMap/EcosystemSection.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { ExternalLinkIcon } from 'lucide-react'

const EcosystemSection = ({ apps }: { apps: any[] }) => {
return (
<div className="grid grid-cols-2 lg:grid-cols-4 xl:grid-cols-5 gap-6 mt-8">
{apps.map((app, index) => {
const logo = app.fieldData.logo
return (
<a
href={`${app.fieldData.link}?utm_source=sei-docs`}
key={index}
target="_blank"
className="flex flex-col border border-gray-200 dark:border-gray-700 rounded-lg overflow-hidden hover:opacity-80 transition-all relative group"
>
<div className="bg-black text-white p-2 absolute rounded-md -right-8 -top-8 group-hover:top-1 group-hover:right-1 transition-all">
<ExternalLinkIcon className="h-4 w-4" />
</div>
{logo && (
<div className="flex flex-col">
<img
src={logo.url}
alt={logo.name}
className="h-full w-full aspect-square"
/>
<div className="truncate bg-gray-100 dark:bg-gray-800 p-4 font-semibold">
{app.fieldData.name}
</div>
</div>
)}
</a>
)
})}
</div>
)
}

export default EcosystemSection
19 changes: 19 additions & 0 deletions components/EcosystemMap/EcosystemSkeleton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
const EcosystemSkeleton = () => {
return (
<div className="flex flex-col gap-6 pt-8">
<div className="w-1/3 h-8 bg-slate-200 rounded-md bg-gradient-to-tr from-zinc-50 to-zinc-200 dark:from-zinc-800 dark:to-zinc-950 animate-pulse" />
<div className="grid grid-cols-4 gap-6">
{Array.from({ length: 8 }).map((_, index) => (
<div
key={index}
className="animate-pulse bg-gradient-to-tr from-zinc-50 to-zinc-200 dark:from-zinc-800 dark:to-zinc-950 rounded-xl flex-col justify-start items-center inline-flex aspect-[2/3] overflow-hidden"
>
<div className="w-full relative bg-gradient-to-tl from-zinc-50 to-zinc-200 dark:from-zinc-800 dark:to-zinc-950 aspect-square" />
</div>
))}
</div>
</div>
)
}

export default EcosystemSkeleton
4 changes: 4 additions & 0 deletions components/EcosystemMap/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export { default as EcosystemDynamicSection } from './EcosystemDynamicSection'
export { default as EcosystemMap } from './EcosystemMap'
export { default as EcosystemSection } from './EcosystemSection'
export { default as EcosystemSkeleton } from './EcosystemSkeleton'
1 change: 1 addition & 0 deletions components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ export * from './ImageWithCaption';
export * from './Logo';
export * from './Nfts';
export * from './VersionFetcher';
export * from "./EcosystemMap";
54 changes: 54 additions & 0 deletions data/ecosystemData.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
export type EcosystemAppLogoType = {
fileId: string;
url: string;
alt: string | null;
};

export type EcosystemFieldData = {
"featured-app": boolean;
profile: string;
link: string;
"sei-only": boolean;
name: string;
slug: string;
logo: EcosystemAppLogoType;
categorie: string;
};

export type EcosystemItem = {
id: string;
cmsLocaleId: string;
lastPublished: string;
lastUpdated: string;
createdOn: string;
isArchived: boolean;
isDraft: boolean;
fieldData: EcosystemFieldData;
};

export type EcosystemResponse = {
data: EcosystemItem[];
};

export async function getSeiEcosystemAppsData(): Promise<EcosystemResponse> {
const url = "http://staging.app-api.seinetwork.io/webflow/ecosystem"; // TODO: Move to ENV
const headers = { Accept: 'application/json' };

try {
const response = await fetch(url, {
method: "GET",
headers,
});

if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}

const data = await response.json();
console.log("Sei Ecosystem data", data);
return data;
} catch (error) {
console.error("Failed to fetch data:", error);
return { data: [] };
}
}
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@
"react-syntax-highlighter": "^15.5.0",
"sharp": "^0.33.4",
"styled-components": "^6.1.11",
"tailwind-merge": "^2.3.0",
"tailwind-merge": "^2.2.1",
"underscore": "^1.13.6",
"viem": "^1.21.4",
"wagmi": "^1.4.13"
},
Expand Down
47 changes: 45 additions & 2 deletions pages/dev-ecosystem-providers/ecosystem-map.mdx
Original file line number Diff line number Diff line change
@@ -1,5 +1,48 @@
import { EcosystemMap, EcosystemDynamicSection } from "../../components";
import { Cards, Card } from 'nextra/components'
import { Wrench, TextCursorInput } from "lucide-react";

# Ecosystem Map

For a comprehensive view of the Sei ecosystem and its various providers, refer to the ecosystem map.
Sei Ecosystem is the epicenter of technological advancement, bringing together creative minds and industry leaders to drive the future of Sei's blockchain technology.

<Cards>
<Card icon={<Wrench />} title="Start building" href="/" />
<Card icon={<TextCursorInput />} title="Join the ecosystem" href="https://sei-forms.typeform.com/join-ecosystem?typeform-source=p12rt1ecint.typeform.com" target="_blank" />
</Cards>

## Consumer Apps

<EcosystemDynamicSection category="Consumer Apps" />

## AI

<EcosystemDynamicSection category="AI" />

## Infastructure

<EcosystemDynamicSection category="Infrastructure" />

## DeFi

<EcosystemDynamicSection category="DeFi" />

## Data & Analytics

<EcosystemDynamicSection category="Data & Analytics" />

## Wallets

<EcosystemDynamicSection category="Wallets" />

## NFTs

<EcosystemDynamicSection category="NFTs" />

## Exchanges & On/Off Ramps

<EcosystemDynamicSection category="Exchanges & On/Off Ramps" />

## Other

## [Sei Ecosystem Map](https://www.sei.io/ecosystem)
<EcosystemDynamicSection category="Other" />
6 changes: 6 additions & 0 deletions pages/dev-ecosystem-providers/wallets.mdx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { EcosystemDynamicSection } from "../../components";

# Wallets

Wallets are essential for managing assets and interacting with the Sei blockchain. There are various types of wallets available, each offering different features and levels of security.
Expand Down Expand Up @@ -31,3 +33,7 @@ There are several other wallets that support the Sei blockchain, particularly th
| **Gem** ||| Seed Phrase | 118 | Software || [Gem Wallet](https://gemwallet.com) |

These additional wallets provide users with more options to manage their Sei assets, ensuring flexibility and convenience based on their preferences.

## Available Wallets

<EcosystemDynamicSection category="Wallets" />
Loading

0 comments on commit 3b0b34d

Please sign in to comment.