Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
} from '@graphprotocol/hypergraph-react';
import { useState } from 'react';

import { Address } from '@/app/schema';
import { Project } from '@/app/schema';
import { Button } from '../ui/button';

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

function PrivateSpace() {
const { name, ready } = useSpace({ mode: 'private' });
const { data: addresses } = useQuery(Address, { mode: 'private' });
const { name, ready, id: spaceId } = useSpace({ mode: 'private' });
const { data: projects } = useQuery(Project, { mode: 'private' });
const { data: publicSpaces } = useSpaces({ mode: 'public' });
const [selectedSpace, setSelectedSpace] = useState<string>('');
const createAddress = useCreateEntity(Address);
const [addressName, setAddressName] = useState('');
const createProject = useCreateEntity(Project);
const [projectName, setProjectName] = useState('');
const [projectDescription, setProjectDescription] = useState('');
const { getSmartSessionClient } = useHypergraphApp();

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

const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
createAddress({ name: addressName, description: 'Beautiful address' });
setAddressName('');
createProject({ name: projectName, description: projectDescription });
setProjectName('');
setProjectDescription('');
};

const publishToPublicSpace = async (address: Address) => {
const publishToPublicSpace = async (project: Project) => {
if (!selectedSpace) {
alert('No space selected');
return;
}
try {
const { ops } = await preparePublish({ entity: address, publicSpace: selectedSpace });
const { ops } = await preparePublish({ entity: project, publicSpace: selectedSpace });
const smartSessionClient = await getSmartSessionClient();
if (!smartSessionClient) {
throw new Error('Missing smartSessionClient');
}
const publishResult = await publishOps({
ops,
space: selectedSpace,
name: 'Publish Address',
name: 'Publish Project',
walletClient: smartSessionClient,
});
console.log(publishResult, ops);
alert('Address published to public space');
alert('Project published to public space');
} catch (error) {
console.error(error);
alert('Error publishing address to public space');
alert('Error publishing project to public space');
}
};

Expand All @@ -79,8 +81,10 @@ function PrivateSpace() {
<div className="container mx-auto px-4 py-8 max-w-4xl">
{/* Header */}
<div className="mb-8">
<h1 className="text-3xl font-bold text-foreground mb-2">{name}</h1>
<p className="text-muted-foreground">Manage your private addresses and publish them to public spaces</p>
<p className="text-slate-600 mt-1 text-sm">Public Space</p>
<h1 className="text-3xl font-bold text-slate-900">{name}</h1>
<p className="text-slate-600 mt-1 text-sm">ID: {spaceId}</p>
<p className="text-muted-foreground mt-6">Manage your private projects and publish them to public spaces</p>
</div>

<div className="grid gap-8 lg:grid-cols-2">
Expand All @@ -94,17 +98,30 @@ function PrivateSpace() {
Address Name
</label>
<input
id="address-name"
id="project-name"
type="text"
value={addressName}
onChange={(e) => setAddressName(e.target.value)}
placeholder="Enter address name..."
value={projectName}
onChange={(e) => setProjectName(e.target.value)}
placeholder="Enter project name..."
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"
required
/>
</div>
<Button type="submit" className="w-full" disabled={!addressName.trim()}>
Create Address
<div className="space-y-2">
<label htmlFor="project-description" className="text-sm font-medium text-card-foreground">
Project Description
</label>
<input
id="project-description"
type="text"
value={projectDescription}
onChange={(e) => setProjectDescription(e.target.value)}
placeholder="Enter project description..."
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"
/>
</div>
<Button type="submit" className="w-full" disabled={!projectName.trim()}>
Create Project
</Button>
</form>
</div>
Expand All @@ -114,18 +131,23 @@ function PrivateSpace() {
<div className="space-y-6">
<div className="bg-card border rounded-lg p-6 shadow-sm">
<h2 className="text-xl font-semibold text-card-foreground mb-4">
Your Addresses ({addresses?.length || 0})
Your Projects ({projects?.length || 0})
</h2>

{addresses && addresses.length > 0 ? (
{projects && projects.length > 0 ? (
<div className="space-y-4">
{addresses.map((address) => (
<div key={address.id} className="border border-border rounded-lg p-4 bg-background">
{projects.map((project) => (
<div key={project.id} className="border border-border rounded-lg p-4 bg-background">
<div className="flex items-center justify-between mb-3">
<h3 className="font-medium text-foreground">{project.name}</h3>
</div>

<div className="flex items-center justify-between mb-3">
<p className="text-xs text-muted-foreground">ID: {project.id}</p>
</div>

<div className="flex items-center justify-between mb-3">
<h3 className="font-medium text-foreground">{address.name}</h3>
<span className="text-xs text-muted-foreground bg-muted px-2 py-1 rounded">
ID: {address.id.slice(0, 8)}...
</span>
<p className="text-sm text-muted-foreground">{project.description}</p>
</div>

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

<Button
onClick={() => publishToPublicSpace(address)}
onClick={() => publishToPublicSpace(project)}
disabled={!selectedSpace}
variant="outline"
size="sm"
Expand Down Expand Up @@ -178,8 +200,8 @@ function PrivateSpace() {
/>
</svg>
</div>
<p className="text-muted-foreground">No addresses created yet</p>
<p className="text-sm text-muted-foreground mt-1">Create your first address using the form</p>
<p className="text-muted-foreground">No projects created yet</p>
<p className="text-sm text-muted-foreground mt-1">Create your first project using the form</p>
</div>
)}
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

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

import { Address } from '@/app/schema';
import { Project } from '@/app/schema';

export function PublicSpaceWrapper({ spaceid }: Readonly<{ spaceid: string }>) {
return (
Expand All @@ -13,8 +13,8 @@ export function PublicSpaceWrapper({ spaceid }: Readonly<{ spaceid: string }>) {
}

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

if (!ready) {
return (
Expand All @@ -33,85 +33,85 @@ function PublicSpace() {
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-6">
<div className="flex items-center justify-between">
<div>
<p className="text-slate-600 mt-1 text-sm">Public Space</p>
<h1 className="text-3xl font-bold text-slate-900">{name}</h1>
<p className="text-slate-600 mt-1">Public Space</p>
<p className="text-slate-600 mt-1 text-sm">ID: {spaceId}</p>
</div>
</div>
</div>

{isPending && <div className="text-center py-16">Loading…</div>}

{/* Main Content */}
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
<div className="bg-white rounded-lg shadow-sm border border-slate-200">
<div className="px-6 py-4 border-b border-slate-200">
<h2 className="text-xl font-semibold text-slate-900">Addresses</h2>
<p className="text-slate-600 text-sm mt-1">
{addresses ? `${addresses.length} addresses found` : 'Loading addresses...'}
</p>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6">
{projects.map((project) => (
<div
key={project.id}
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"
>
{/* Gradient overlay */}
<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" />

<div className="p-6">
{!addresses ? (
<div className="space-y-3">
{[...Array(3)].map((_, i) => (
<div key={i} className="animate-pulse">
<div className="h-4 bg-slate-200 rounded w-3/4" />
</div>
))}
</div>
) : addresses.length > 0 ? (
<div className="grid gap-3">
{addresses.map((address) => (
<div
key={address.id}
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"
>
<div className="flex items-center justify-between">
<div className="flex items-center space-x-3">
<div className="w-8 h-8 bg-blue-100 rounded-full flex items-center justify-center">
<span className="text-blue-600 font-medium text-sm">
{address.name.charAt(0).toUpperCase()}
</span>
</div>
<div>
<h3 className="font-medium text-slate-900 group-hover:text-blue-600 transition-colors">
{address.name}
</h3>
<p className="text-sm text-slate-500">Address ID: {address.id}</p>
</div>
</div>
<div className="opacity-0 group-hover:opacity-100 transition-opacity">
<svg className="w-5 h-5 text-slate-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" />
</svg>
</div>
</div>
</div>
))}
</div>
) : (
<div className="text-center py-12">
<div className="w-16 h-16 bg-slate-100 rounded-full flex items-center justify-center mx-auto mb-4">
<svg className="w-8 h-8 text-slate-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
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"
/>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M15 11a3 3 0 11-6 0 3 3 0 016 0z"
/>
</svg>
{/* Content */}
<div className="relative p-6">
{/* Project icon/avatar */}
<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">
<span className="text-white font-bold text-lg">{project.name.charAt(0).toUpperCase()}</span>
</div>
<h3 className="text-lg font-medium text-slate-900 mb-2">No addresses found</h3>
<p className="text-slate-600">This space doesn&apos;t have any addresses yet.</p>

{/* Project name */}
<h3 className="text-xl font-bold text-gray-900 mb-2 group-hover:text-blue-600 transition-colors duration-300">
{project.name}
</h3>

{/* Project ID */}
<p className="text-[10px] text-gray-500 mb-2 font-mono">{project.id}</p>

{/* Project description */}
{project.description && (
<p className="text-sm text-gray-600 mb-2 line-clamp-2">{project.description}</p>
)}

{/* Project xUrl */}
{project.xUrl && (
<a
href={project.xUrl}
target="_blank"
rel="noopener noreferrer"
className="text-sm text-blue-600 hover:text-blue-800 transition-colors duration-200 flex items-center gap-1"
>
<svg className="w-4 h-4" fill="currentColor" viewBox="0 0 24 24">
<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" />
</svg>
View on X
</a>
)}
</div>
)}
</div>

{/* Decorative corner accent */}
<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" />
</div>
))}
</div>

{/* Empty state */}
{isPending === false && projects.length === 0 && (
<div className="text-center py-16">
<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">
<svg className="w-12 h-12 text-blue-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
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"
/>
</svg>
</div>
<h3 className="text-xl font-semibold text-gray-900 mb-2">No Projects Found</h3>
<p className="text-gray-500">There are currently no public projects available to explore.</p>
</div>
)}
</div>
</div>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,20 @@ import { ExploreTabs } from '../../Components/explore-tabs';
export default function ExplorePublicKnowledgeLayout({ children }: { children: React.ReactNode }) {
return (
<div className="container mx-auto px-4 py-8">
<div className="text-center mb-12">
<div className="text-center mb-6">
<h1 className="text-4xl font-bold mb-4 bg-gradient-to-r from-blue-600 to-purple-600 bg-clip-text text-transparent">
Explore Public Knowledge
</h1>
<p className="text-lg text-muted-foreground max-w-2xl mx-auto">
This page demonstrates how to query public data from a space. No authentication is required.
This page demonstrates how to query public data from the public space{' '}
<span className="inline-flex items-center rounded-full border bg-accent/60 text-accent-foreground px-2 py-0.5 text-sm align-middle">
Crypto
</span>{' '}
with the ID{' '}
<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">
b2565802-3118-47be-91f2-e59170735bac
</span>
. No authentication is required.
</p>
</div>

Expand Down
7 changes: 0 additions & 7 deletions apps/create-hypergraph/template-nextjs/app/mapping.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,6 @@ import type { Mapping } from '@graphprotocol/hypergraph';
import { Id } from '@graphprotocol/hypergraph';

export const mapping: Mapping.Mapping = {
Address: {
typeIds: [Id('5c6e72fb-8340-47c0-8281-8be159ecd495')],
properties: {
name: Id('a126ca53-0c8e-48d5-b888-82c734c38935'),
description: Id('9b1f76ff-9711-404c-861e-59dc3fa7d037'),
},
},
Image: {
typeIds: [Id('ba4e4146-0010-499d-a0a3-caaa7f579d0e')],
properties: {
Expand Down
5 changes: 0 additions & 5 deletions apps/create-hypergraph/template-nextjs/app/schema.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
import { Entity, Type } from '@graphprotocol/hypergraph';

export class Address extends Entity.Class<Address>('Address')({
name: Type.String,
description: Type.String,
}) {}

export class Image extends Entity.Class<Image>('Image')({
url: Type.String,
}) {}
Expand Down
Loading
Loading