diff --git a/.changeset/clean-spies-stare.md b/.changeset/clean-spies-stare.md new file mode 100644 index 00000000..3ecf32f7 --- /dev/null +++ b/.changeset/clean-spies-stare.md @@ -0,0 +1,6 @@ +--- +"create-hypergraph": patch +--- + +improve projects listing in both templates + \ No newline at end of file diff --git a/apps/create-hypergraph/template-nextjs/Components/GraphImage.tsx b/apps/create-hypergraph/template-nextjs/Components/GraphImage.tsx new file mode 100644 index 00000000..0e51364d --- /dev/null +++ b/apps/create-hypergraph/template-nextjs/Components/GraphImage.tsx @@ -0,0 +1,14 @@ +function getImageUrl(src: string | undefined | Blob) { + if (!src || typeof src !== 'string') return src; + const image = src.split('ipfs://'); + if (image.length === 2) { + return `https://gateway.lighthouse.storage/ipfs/${image[1]}`; + } + return src; +} + +export function GraphImage( + props: React.DetailedHTMLProps, HTMLImageElement>, +) { + return ; +} diff --git a/apps/create-hypergraph/template-nextjs/Components/PublicKnowledge/Explore.tsx b/apps/create-hypergraph/template-nextjs/Components/PublicKnowledge/Explore.tsx index 01a157b5..cd7ff595 100644 --- a/apps/create-hypergraph/template-nextjs/Components/PublicKnowledge/Explore.tsx +++ b/apps/create-hypergraph/template-nextjs/Components/PublicKnowledge/Explore.tsx @@ -1,62 +1,127 @@ 'use client'; import { useQuery } from '@graphprotocol/hypergraph-react'; +import { useState } from 'react'; import { Project } from '../../app/schema'; +import { GraphImage } from '../GraphImage'; export function PublicKnowledgeExplorer() { + const [searchTerm, setSearchTerm] = useState(''); + const { data: projects, isPending } = useQuery(Project, { mode: 'public', space: 'b2565802-3118-47be-91f2-e59170735bac', first: 40, + include: { avatar: {} }, + filter: { + name: { + // contains is case sensitive + contains: searchTerm, + }, + }, }); - // empty state - if (isPending === false && projects.length === 0) { - return ( -
-
- - - + return ( + <> + {/* Search UI */} +
+
+
+ + + +
+ setSearchTerm(e.target.value)} + placeholder="Search projects..." + className="block w-full pl-10 pr-3 py-3 border border-gray-300 rounded-xl leading-5 bg-white placeholder-gray-500 focus:outline-none focus:placeholder-gray-400 focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition-all duration-200" + />
-

No Projects Found

-

There are currently no public projects available to explore.

- ); - } - return ( -
- {projects.map((project) => ( -
- {/* Gradient overlay */} -
- - {/* Content */} -
- {/* Project icon/avatar */} -
- {project.name.charAt(0).toUpperCase()} +
+ {projects.map((project) => ( +
+ {/* Gradient overlay */} +
+ + {/* Content */} +
+ {/* Project icon/avatar */} +
+ {project.avatar?.[0]?.url ? ( + + ) : ( + {project.name.charAt(0).toUpperCase()} + )} +
+ + {/* Project name */} +

+ {project.name} +

+ + {/* Project ID */} +

{project.id}

+ + {/* Project description */} + {project.description &&

{project.description}

} + + {/* Project xUrl */} + {project.xUrl && ( + + + + + View on X + + )}
- {/* Project name */} -

- {project.name} -

+ {/* Decorative corner accent */} +
+ ))} +
- {/* Decorative corner accent */} -
+ {/* Empty state */} + {isPending === false && projects.length === 0 && ( +
+
+ + + +
+

No Projects Found

+

There are currently no public projects available to explore.

- ))} -
+ )} + ); } diff --git a/apps/create-hypergraph/template-nextjs/app/mapping.ts b/apps/create-hypergraph/template-nextjs/app/mapping.ts index 6c0cf6a2..5a599dfb 100644 --- a/apps/create-hypergraph/template-nextjs/app/mapping.ts +++ b/apps/create-hypergraph/template-nextjs/app/mapping.ts @@ -9,10 +9,21 @@ export const mapping: Mapping.Mapping = { description: Id('9b1f76ff-9711-404c-861e-59dc3fa7d037'), }, }, + Image: { + typeIds: [Id('ba4e4146-0010-499d-a0a3-caaa7f579d0e')], + properties: { + url: Id('8a743832-c094-4a62-b665-0c3cc2f9c7bc'), + }, + }, Project: { typeIds: [Id('484a18c5-030a-499c-b0f2-ef588ff16d50')], properties: { name: Id('a126ca53-0c8e-48d5-b888-82c734c38935'), + description: Id('9b1f76ff-9711-404c-861e-59dc3fa7d037'), + xUrl: Id('0d625978-4b3c-4b57-a86f-de45c997c73c'), + }, + relations: { + avatar: Id('1155beff-fad5-49b7-a2e0-da4777b8792c'), }, }, }; diff --git a/apps/create-hypergraph/template-nextjs/app/schema.ts b/apps/create-hypergraph/template-nextjs/app/schema.ts index d3805876..4e869b87 100644 --- a/apps/create-hypergraph/template-nextjs/app/schema.ts +++ b/apps/create-hypergraph/template-nextjs/app/schema.ts @@ -5,6 +5,13 @@ export class Address extends Entity.Class
('Address')({ description: Type.String, }) {} +export class Image extends Entity.Class('Image')({ + url: Type.String, +}) {} + export class Project extends Entity.Class('Project')({ name: Type.String, + description: Type.optional(Type.String), + xUrl: Type.optional(Type.String), + avatar: Type.Relation(Image), }) {} diff --git a/apps/create-hypergraph/template-vite-react/src/components/graph-image.tsx b/apps/create-hypergraph/template-vite-react/src/components/graph-image.tsx new file mode 100644 index 00000000..6113e394 --- /dev/null +++ b/apps/create-hypergraph/template-vite-react/src/components/graph-image.tsx @@ -0,0 +1,14 @@ +function getImageUrl(src: string | undefined) { + if (!src || typeof src !== 'string') return src; + const image = src.split('ipfs://'); + if (image.length === 2) { + return `https://gateway.lighthouse.storage/ipfs/${image[1]}`; + } + return src; +} + +export function GraphImage( + props: React.DetailedHTMLProps, HTMLImageElement>, +) { + return ; +} diff --git a/apps/create-hypergraph/template-vite-react/src/mapping.ts b/apps/create-hypergraph/template-vite-react/src/mapping.ts index b6431a44..5a599dfb 100644 --- a/apps/create-hypergraph/template-vite-react/src/mapping.ts +++ b/apps/create-hypergraph/template-vite-react/src/mapping.ts @@ -9,10 +9,21 @@ export const mapping: Mapping.Mapping = { description: Id('9b1f76ff-9711-404c-861e-59dc3fa7d037'), }, }, + Image: { + typeIds: [Id('ba4e4146-0010-499d-a0a3-caaa7f579d0e')], + properties: { + url: Id('8a743832-c094-4a62-b665-0c3cc2f9c7bc'), + }, + }, Project: { typeIds: [Id('484a18c5-030a-499c-b0f2-ef588ff16d50')], properties: { name: Id('a126ca53-0c8e-48d5-b888-82c734c38935'), + description: Id('9b1f76ff-9711-404c-861e-59dc3fa7d037'), + xUrl: Id('0d625978-4b3c-4b57-a86f-de45c997c73c'), + }, + relations: { + avatar: Id('1155beff-fad5-49b7-a2e0-da4777b8792c'), }, }, -}; \ No newline at end of file +}; diff --git a/apps/create-hypergraph/template-vite-react/src/routes/explore-public-knowledge.tsx b/apps/create-hypergraph/template-vite-react/src/routes/explore-public-knowledge.tsx index 86476fb7..6f37328c 100644 --- a/apps/create-hypergraph/template-vite-react/src/routes/explore-public-knowledge.tsx +++ b/apps/create-hypergraph/template-vite-react/src/routes/explore-public-knowledge.tsx @@ -1,16 +1,27 @@ +import { GraphImage } from '@/components/graph-image'; import { Project } from '@/schema'; import { useQuery } from '@graphprotocol/hypergraph-react'; import { createFileRoute } from '@tanstack/react-router'; +import { useState } from 'react'; export const Route = createFileRoute('/explore-public-knowledge')({ component: ExplorePublicKnowledge, }); function ExplorePublicKnowledge() { + const [searchTerm, setSearchTerm] = useState(''); + const { data: projects, isPending } = useQuery(Project, { mode: 'public', space: 'b2565802-3118-47be-91f2-e59170735bac', first: 40, + include: { avatar: {} }, + filter: { + name: { + // contains is case sensitive + contains: searchTerm, + }, + }, }); return ( @@ -24,6 +35,29 @@ function ExplorePublicKnowledge() {

+ {/* Search UI */} +
+
+
+ + + +
+ setSearchTerm(e.target.value)} + placeholder="Search projects..." + className="block w-full pl-10 pr-3 py-3 border border-gray-300 rounded-xl leading-5 bg-white placeholder-gray-500 focus:outline-none focus:placeholder-gray-400 focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition-all duration-200" + /> +
+
+
{projects.map((project) => (
{/* Project icon/avatar */} -
- {project.name.charAt(0).toUpperCase()} +
+ {project.avatar?.[0]?.url ? ( + + ) : ( + {project.name.charAt(0).toUpperCase()} + )}
{/* Project name */}

{project.name}

+ + {/* Project ID */} +

{project.id}

+ + {/* Project description */} + {project.description &&

{project.description}

} + + {/* Project xUrl */} + {project.xUrl && ( + + + + + View on X + + )}
{/* Decorative corner accent */} diff --git a/apps/create-hypergraph/template-vite-react/src/schema.ts b/apps/create-hypergraph/template-vite-react/src/schema.ts index d3805876..4e869b87 100644 --- a/apps/create-hypergraph/template-vite-react/src/schema.ts +++ b/apps/create-hypergraph/template-vite-react/src/schema.ts @@ -5,6 +5,13 @@ export class Address extends Entity.Class
('Address')({ description: Type.String, }) {} +export class Image extends Entity.Class('Image')({ + url: Type.String, +}) {} + export class Project extends Entity.Class('Project')({ name: Type.String, + description: Type.optional(Type.String), + xUrl: Type.optional(Type.String), + avatar: Type.Relation(Image), }) {}