Skip to content

Commit dcc05b3

Browse files
authored
improve template (#471)
1 parent 53cd9fc commit dcc05b3

File tree

14 files changed

+476
-424
lines changed

14 files changed

+476
-424
lines changed

.changeset/easy-nails-wish.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"create-hypergraph": patch
3+
---
4+
5+
improve templates (use Projects instead of Address, show space IDs, show Project IDs)
6+

apps/create-hypergraph/template-nextjs/Components/Space/PrivateSpace.tsx

Lines changed: 57 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import {
1212
} from '@graphprotocol/hypergraph-react';
1313
import { useState } from 'react';
1414

15-
import { Address } from '@/app/schema';
15+
import { Project } from '@/app/schema';
1616
import { Button } from '../ui/button';
1717

1818
export function PrivateSpaceWrapper({ spaceid }: Readonly<{ spaceid: string }>) {
@@ -24,12 +24,13 @@ export function PrivateSpaceWrapper({ spaceid }: Readonly<{ spaceid: string }>)
2424
}
2525

2626
function PrivateSpace() {
27-
const { name, ready } = useSpace({ mode: 'private' });
28-
const { data: addresses } = useQuery(Address, { mode: 'private' });
27+
const { name, ready, id: spaceId } = useSpace({ mode: 'private' });
28+
const { data: projects } = useQuery(Project, { mode: 'private' });
2929
const { data: publicSpaces } = useSpaces({ mode: 'public' });
3030
const [selectedSpace, setSelectedSpace] = useState<string>('');
31-
const createAddress = useCreateEntity(Address);
32-
const [addressName, setAddressName] = useState('');
31+
const createProject = useCreateEntity(Project);
32+
const [projectName, setProjectName] = useState('');
33+
const [projectDescription, setProjectDescription] = useState('');
3334
const { getSmartSessionClient } = useHypergraphApp();
3435

3536
if (!ready) {
@@ -45,32 +46,33 @@ function PrivateSpace() {
4546

4647
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
4748
e.preventDefault();
48-
createAddress({ name: addressName, description: 'Beautiful address' });
49-
setAddressName('');
49+
createProject({ name: projectName, description: projectDescription });
50+
setProjectName('');
51+
setProjectDescription('');
5052
};
5153

52-
const publishToPublicSpace = async (address: Address) => {
54+
const publishToPublicSpace = async (project: Project) => {
5355
if (!selectedSpace) {
5456
alert('No space selected');
5557
return;
5658
}
5759
try {
58-
const { ops } = await preparePublish({ entity: address, publicSpace: selectedSpace });
60+
const { ops } = await preparePublish({ entity: project, publicSpace: selectedSpace });
5961
const smartSessionClient = await getSmartSessionClient();
6062
if (!smartSessionClient) {
6163
throw new Error('Missing smartSessionClient');
6264
}
6365
const publishResult = await publishOps({
6466
ops,
6567
space: selectedSpace,
66-
name: 'Publish Address',
68+
name: 'Publish Project',
6769
walletClient: smartSessionClient,
6870
});
6971
console.log(publishResult, ops);
70-
alert('Address published to public space');
72+
alert('Project published to public space');
7173
} catch (error) {
7274
console.error(error);
73-
alert('Error publishing address to public space');
75+
alert('Error publishing project to public space');
7476
}
7577
};
7678

@@ -79,32 +81,47 @@ function PrivateSpace() {
7981
<div className="container mx-auto px-4 py-8 max-w-4xl">
8082
{/* Header */}
8183
<div className="mb-8">
82-
<h1 className="text-3xl font-bold text-foreground mb-2">{name}</h1>
83-
<p className="text-muted-foreground">Manage your private addresses and publish them to public spaces</p>
84+
<p className="text-slate-600 mt-1 text-sm">Private Space</p>
85+
<h1 className="text-3xl font-bold text-slate-900">{name}</h1>
86+
<p className="text-slate-600 mt-1 text-sm">ID: {spaceId}</p>
87+
<p className="text-muted-foreground mt-6">Manage your private projects and publish them to public spaces</p>
8488
</div>
8589

8690
<div className="grid gap-8 lg:grid-cols-2">
87-
{/* Create Address Form */}
91+
{/* Create Project Form */}
8892
<div className="space-y-6">
8993
<div className="bg-card border rounded-lg p-6 shadow-sm">
90-
<h2 className="text-xl font-semibold text-card-foreground mb-4">Create New Address</h2>
94+
<h2 className="text-xl font-semibold text-card-foreground mb-4">Create New Project</h2>
9195
<form onSubmit={handleSubmit} className="space-y-4">
9296
<div className="space-y-2">
93-
<label htmlFor="address-name" className="text-sm font-medium text-card-foreground">
94-
Address Name
97+
<label htmlFor="project-name" className="text-sm font-medium text-card-foreground">
98+
Project Name
9599
</label>
96100
<input
97-
id="address-name"
101+
id="project-name"
98102
type="text"
99-
value={addressName}
100-
onChange={(e) => setAddressName(e.target.value)}
101-
placeholder="Enter address name..."
103+
value={projectName}
104+
onChange={(e) => setProjectName(e.target.value)}
105+
placeholder="Enter project name..."
102106
className="w-full px-3 py-2 border border-input bg-background rounded-md text-sm transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:border-transparent"
103107
required
104108
/>
105109
</div>
106-
<Button type="submit" className="w-full" disabled={!addressName.trim()}>
107-
Create Address
110+
<div className="space-y-2">
111+
<label htmlFor="project-description" className="text-sm font-medium text-card-foreground">
112+
Project Description
113+
</label>
114+
<input
115+
id="project-description"
116+
type="text"
117+
value={projectDescription}
118+
onChange={(e) => setProjectDescription(e.target.value)}
119+
placeholder="Enter project description..."
120+
className="w-full px-3 py-2 border border-input bg-background rounded-md text-sm transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:border-transparent"
121+
/>
122+
</div>
123+
<Button type="submit" className="w-full" disabled={!projectName.trim()}>
124+
Create Project
108125
</Button>
109126
</form>
110127
</div>
@@ -114,18 +131,23 @@ function PrivateSpace() {
114131
<div className="space-y-6">
115132
<div className="bg-card border rounded-lg p-6 shadow-sm">
116133
<h2 className="text-xl font-semibold text-card-foreground mb-4">
117-
Your Addresses ({addresses?.length || 0})
134+
Your Projects ({projects?.length || 0})
118135
</h2>
119136

120-
{addresses && addresses.length > 0 ? (
137+
{projects && projects.length > 0 ? (
121138
<div className="space-y-4">
122-
{addresses.map((address) => (
123-
<div key={address.id} className="border border-border rounded-lg p-4 bg-background">
139+
{projects.map((project) => (
140+
<div key={project.id} className="border border-border rounded-lg p-4 bg-background">
141+
<div className="flex items-center justify-between mb-3">
142+
<h3 className="font-medium text-foreground">{project.name}</h3>
143+
</div>
144+
145+
<div className="flex items-center justify-between mb-3">
146+
<p className="text-xs text-muted-foreground">ID: {project.id}</p>
147+
</div>
148+
124149
<div className="flex items-center justify-between mb-3">
125-
<h3 className="font-medium text-foreground">{address.name}</h3>
126-
<span className="text-xs text-muted-foreground bg-muted px-2 py-1 rounded">
127-
ID: {address.id.slice(0, 8)}...
128-
</span>
150+
<p className="text-sm text-muted-foreground">{project.description}</p>
129151
</div>
130152

131153
<div className="space-y-3">
@@ -149,7 +171,7 @@ function PrivateSpace() {
149171
</div>
150172

151173
<Button
152-
onClick={() => publishToPublicSpace(address)}
174+
onClick={() => publishToPublicSpace(project)}
153175
disabled={!selectedSpace}
154176
variant="outline"
155177
size="sm"
@@ -178,8 +200,8 @@ function PrivateSpace() {
178200
/>
179201
</svg>
180202
</div>
181-
<p className="text-muted-foreground">No addresses created yet</p>
182-
<p className="text-sm text-muted-foreground mt-1">Create your first address using the form</p>
203+
<p className="text-muted-foreground">No projects created yet</p>
204+
<p className="text-sm text-muted-foreground mt-1">Create your first project using the form</p>
183205
</div>
184206
)}
185207
</div>

apps/create-hypergraph/template-nextjs/Components/Space/PublicSpace.tsx

Lines changed: 71 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import { HypergraphSpaceProvider, useQuery, useSpace } from '@graphprotocol/hypergraph-react';
44

5-
import { Address } from '@/app/schema';
5+
import { Project } from '@/app/schema';
66

77
export function PublicSpaceWrapper({ spaceid }: Readonly<{ spaceid: string }>) {
88
return (
@@ -13,8 +13,8 @@ export function PublicSpaceWrapper({ spaceid }: Readonly<{ spaceid: string }>) {
1313
}
1414

1515
function PublicSpace() {
16-
const { ready, name } = useSpace({ mode: 'public' });
17-
const { data: addresses } = useQuery(Address, { mode: 'public' });
16+
const { ready, name, id: spaceId } = useSpace({ mode: 'public' });
17+
const { data: projects, isPending } = useQuery(Project, { mode: 'public' });
1818

1919
if (!ready) {
2020
return (
@@ -33,85 +33,85 @@ function PublicSpace() {
3333
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-6">
3434
<div className="flex items-center justify-between">
3535
<div>
36+
<p className="text-slate-600 mt-1 text-sm">Public Space</p>
3637
<h1 className="text-3xl font-bold text-slate-900">{name}</h1>
37-
<p className="text-slate-600 mt-1">Public Space</p>
38+
<p className="text-slate-600 mt-1 text-sm">ID: {spaceId}</p>
3839
</div>
3940
</div>
4041
</div>
4142

43+
{isPending && <div className="text-center py-16">Loading…</div>}
44+
4245
{/* Main Content */}
4346
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
44-
<div className="bg-white rounded-lg shadow-sm border border-slate-200">
45-
<div className="px-6 py-4 border-b border-slate-200">
46-
<h2 className="text-xl font-semibold text-slate-900">Addresses</h2>
47-
<p className="text-slate-600 text-sm mt-1">
48-
{addresses ? `${addresses.length} addresses found` : 'Loading addresses...'}
49-
</p>
50-
</div>
47+
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6">
48+
{projects.map((project) => (
49+
<div
50+
key={project.id}
51+
className="group relative bg-white rounded-2xl shadow-lg hover:shadow-2xl transition-all duration-300 overflow-hidden border border-gray-100 hover:border-blue-200 transform hover:-translate-y-1 z-10"
52+
>
53+
{/* Gradient overlay */}
54+
<div className="absolute inset-0 bg-gradient-to-br from-blue-50 to-purple-50 opacity-0 group-hover:opacity-100 transition-opacity duration-300" />
5155

52-
<div className="p-6">
53-
{!addresses ? (
54-
<div className="space-y-3">
55-
{[...Array(3)].map((_, i) => (
56-
<div key={i} className="animate-pulse">
57-
<div className="h-4 bg-slate-200 rounded w-3/4" />
58-
</div>
59-
))}
60-
</div>
61-
) : addresses.length > 0 ? (
62-
<div className="grid gap-3">
63-
{addresses.map((address) => (
64-
<div
65-
key={address.id}
66-
className="group p-4 rounded-lg border border-slate-200 hover:border-slate-300 hover:shadow-sm transition-all duration-200 bg-slate-50 hover:bg-white"
67-
>
68-
<div className="flex items-center justify-between">
69-
<div className="flex items-center space-x-3">
70-
<div className="w-8 h-8 bg-blue-100 rounded-full flex items-center justify-center">
71-
<span className="text-blue-600 font-medium text-sm">
72-
{address.name.charAt(0).toUpperCase()}
73-
</span>
74-
</div>
75-
<div>
76-
<h3 className="font-medium text-slate-900 group-hover:text-blue-600 transition-colors">
77-
{address.name}
78-
</h3>
79-
<p className="text-sm text-slate-500">Address ID: {address.id}</p>
80-
</div>
81-
</div>
82-
<div className="opacity-0 group-hover:opacity-100 transition-opacity">
83-
<svg className="w-5 h-5 text-slate-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
84-
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" />
85-
</svg>
86-
</div>
87-
</div>
88-
</div>
89-
))}
90-
</div>
91-
) : (
92-
<div className="text-center py-12">
93-
<div className="w-16 h-16 bg-slate-100 rounded-full flex items-center justify-center mx-auto mb-4">
94-
<svg className="w-8 h-8 text-slate-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
95-
<path
96-
strokeLinecap="round"
97-
strokeLinejoin="round"
98-
strokeWidth={2}
99-
d="M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z"
100-
/>
101-
<path
102-
strokeLinecap="round"
103-
strokeLinejoin="round"
104-
strokeWidth={2}
105-
d="M15 11a3 3 0 11-6 0 3 3 0 016 0z"
106-
/>
107-
</svg>
56+
{/* Content */}
57+
<div className="relative p-6">
58+
{/* Project icon/avatar */}
59+
<div className="w-12 h-12 bg-gradient-to-br from-blue-500 to-purple-600 rounded-xl flex items-center justify-center mb-4 group-hover:scale-110 transition-transform duration-300 overflow-hidden">
60+
<span className="text-white font-bold text-lg">{project.name.charAt(0).toUpperCase()}</span>
10861
</div>
109-
<h3 className="text-lg font-medium text-slate-900 mb-2">No addresses found</h3>
110-
<p className="text-slate-600">This space doesn&apos;t have any addresses yet.</p>
62+
63+
{/* Project name */}
64+
<h3 className="text-xl font-bold text-gray-900 mb-2 group-hover:text-blue-600 transition-colors duration-300">
65+
{project.name}
66+
</h3>
67+
68+
{/* Project ID */}
69+
<p className="text-[10px] text-gray-500 mb-2 font-mono">{project.id}</p>
70+
71+
{/* Project description */}
72+
{project.description && (
73+
<p className="text-sm text-gray-600 mb-2 line-clamp-2">{project.description}</p>
74+
)}
75+
76+
{/* Project xUrl */}
77+
{project.xUrl && (
78+
<a
79+
href={project.xUrl}
80+
target="_blank"
81+
rel="noopener noreferrer"
82+
className="text-sm text-blue-600 hover:text-blue-800 transition-colors duration-200 flex items-center gap-1"
83+
>
84+
<svg className="w-4 h-4" fill="currentColor" viewBox="0 0 24 24">
85+
<path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z" />
86+
</svg>
87+
View on X
88+
</a>
89+
)}
11190
</div>
112-
)}
113-
</div>
91+
92+
{/* Decorative corner accent */}
93+
<div className="absolute top-0 right-0 w-16 h-16 bg-gradient-to-br from-blue-400 to-purple-500 opacity-10 group-hover:opacity-20 transition-opacity duration-300 transform rotate-45 translate-x-8 -translate-y-8" />
94+
</div>
95+
))}
11496
</div>
97+
98+
{/* Empty state */}
99+
{isPending === false && projects.length === 0 && (
100+
<div className="text-center py-16">
101+
<div className="w-24 h-24 bg-gradient-to-br from-blue-100 to-purple-100 rounded-full flex items-center justify-center mx-auto mb-6">
102+
<svg className="w-12 h-12 text-blue-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
103+
<path
104+
strokeLinecap="round"
105+
strokeLinejoin="round"
106+
strokeWidth={2}
107+
d="M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10"
108+
/>
109+
</svg>
110+
</div>
111+
<h3 className="text-xl font-semibold text-gray-900 mb-2">No Projects Found</h3>
112+
<p className="text-gray-500">There are currently no public projects available to explore.</p>
113+
</div>
114+
)}
115115
</div>
116116
</div>
117117
);

apps/create-hypergraph/template-nextjs/app/explore-public-knowledge/layout.tsx

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,20 @@ import { ExploreTabs } from '../../Components/explore-tabs';
33
export default function ExplorePublicKnowledgeLayout({ children }: { children: React.ReactNode }) {
44
return (
55
<div className="container mx-auto px-4 py-8">
6-
<div className="text-center mb-12">
6+
<div className="text-center mb-6">
77
<h1 className="text-4xl font-bold mb-4 bg-gradient-to-r from-blue-600 to-purple-600 bg-clip-text text-transparent">
88
Explore Public Knowledge
99
</h1>
1010
<p className="text-lg text-muted-foreground max-w-2xl mx-auto">
11-
This page demonstrates how to query public data from a space. No authentication is required.
11+
This page demonstrates how to query public data from the public space{' '}
12+
<span className="inline-flex items-center rounded-full border bg-accent/60 text-accent-foreground px-2 py-0.5 text-sm align-middle">
13+
Crypto
14+
</span>{' '}
15+
with the ID{' '}
16+
<span className="inline-flex items-center rounded-full border bg-accent/60 text-accent-foreground px-2 py-0.5 text-xs font-mono align-middle">
17+
b2565802-3118-47be-91f2-e59170735bac
18+
</span>
19+
. No authentication is required.
1220
</p>
1321
</div>
1422

apps/create-hypergraph/template-nextjs/app/mapping.ts

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,6 @@ import type { Mapping } from '@graphprotocol/hypergraph';
22
import { Id } from '@graphprotocol/hypergraph';
33

44
export const mapping: Mapping.Mapping = {
5-
Address: {
6-
typeIds: [Id('5c6e72fb-8340-47c0-8281-8be159ecd495')],
7-
properties: {
8-
name: Id('a126ca53-0c8e-48d5-b888-82c734c38935'),
9-
description: Id('9b1f76ff-9711-404c-861e-59dc3fa7d037'),
10-
},
11-
},
125
Image: {
136
typeIds: [Id('ba4e4146-0010-499d-a0a3-caaa7f579d0e')],
147
properties: {

0 commit comments

Comments
 (0)