working example-webapp-react. ready for SoSy2025!

master
Niko PLP 16 hours ago
parent f107b5726d
commit ea021aa198
  1. 68
      ng-sdk-js/example-webapp-react/src/.ldo/contact.context.ts
  2. 115
      ng-sdk-js/example-webapp-react/src/.ldo/contact.schema.ts
  3. 19
      ng-sdk-js/example-webapp-react/src/.ldo/contact.shapeTypes.ts
  4. 37
      ng-sdk-js/example-webapp-react/src/.ldo/contact.typings.ts
  5. 26
      ng-sdk-js/example-webapp-react/src/.shapes/contact.shex
  6. 55
      ng-sdk-js/example-webapp-react/src/App.css
  7. 23
      ng-sdk-js/example-webapp-react/src/App.tsx
  8. 35
      ng-sdk-js/example-webapp-react/src/Contact.tsx
  9. 40
      ng-sdk-js/example-webapp-react/src/Contacts.tsx
  10. 30
      ng-sdk-js/example-webapp-react/src/MakeContact.tsx

@ -0,0 +1,68 @@
import { LdoJsonldContext } from "@ldo/ldo";
/**
* =============================================================================
* contactContext: JSONLD Context for contact
* =============================================================================
*/
export const contactContext: LdoJsonldContext = {
type: {
"@id": "@type",
},
Individual: {
"@id": "http://www.w3.org/2006/vcard/ns#Individual",
"@context": {
type: {
"@id": "@type",
},
fn: {
"@id": "http://www.w3.org/2006/vcard/ns#fn",
"@type": "http://www.w3.org/2001/XMLSchema#string",
},
hasEmail: {
"@id": "http://www.w3.org/2006/vcard/ns#hasEmail",
"@type": "http://www.w3.org/2001/XMLSchema#string",
},
},
},
Person: {
"@id": "http://schema.org/Person",
"@context": {
type: {
"@id": "@type",
},
fn: {
"@id": "http://www.w3.org/2006/vcard/ns#fn",
"@type": "http://www.w3.org/2001/XMLSchema#string",
},
hasEmail: {
"@id": "http://www.w3.org/2006/vcard/ns#hasEmail",
"@type": "http://www.w3.org/2001/XMLSchema#string",
},
},
},
Person2: {
"@id": "http://xmlns.com/foaf/0.1/Person",
"@context": {
type: {
"@id": "@type",
},
fn: {
"@id": "http://www.w3.org/2006/vcard/ns#fn",
"@type": "http://www.w3.org/2001/XMLSchema#string",
},
hasEmail: {
"@id": "http://www.w3.org/2006/vcard/ns#hasEmail",
"@type": "http://www.w3.org/2001/XMLSchema#string",
},
},
},
fn: {
"@id": "http://www.w3.org/2006/vcard/ns#fn",
"@type": "http://www.w3.org/2001/XMLSchema#string",
},
hasEmail: {
"@id": "http://www.w3.org/2006/vcard/ns#hasEmail",
"@type": "http://www.w3.org/2001/XMLSchema#string",
},
};

@ -0,0 +1,115 @@
import { Schema } from "shexj";
/**
* =============================================================================
* contactSchema: ShexJ Schema for contact
* =============================================================================
*/
export const contactSchema: Schema = {
type: "Schema",
shapes: [
{
id: "did:ng:n:g:x:social:contact#NGSocialContact",
type: "ShapeDecl",
shapeExpr: {
type: "Shape",
expression: {
type: "EachOf",
expressions: [
{
type: "TripleConstraint",
predicate: "http://www.w3.org/1999/02/22-rdf-syntax-ns#type",
valueExpr: {
type: "NodeConstraint",
values: ["http://www.w3.org/2006/vcard/ns#Individual"],
},
annotations: [
{
type: "Annotation",
predicate: "http://www.w3.org/2000/01/rdf-schema#comment",
object: {
value: "Defines the node as an Individual (from vcard)",
},
},
],
},
{
type: "TripleConstraint",
predicate: "http://www.w3.org/1999/02/22-rdf-syntax-ns#type",
valueExpr: {
type: "NodeConstraint",
values: ["http://schema.org/Person"],
},
annotations: [
{
type: "Annotation",
predicate: "http://www.w3.org/2000/01/rdf-schema#comment",
object: {
value: "Defines the node as a Person (from Schema.org)",
},
},
],
},
{
type: "TripleConstraint",
predicate: "http://www.w3.org/1999/02/22-rdf-syntax-ns#type",
valueExpr: {
type: "NodeConstraint",
values: ["http://xmlns.com/foaf/0.1/Person"],
},
annotations: [
{
type: "Annotation",
predicate: "http://www.w3.org/2000/01/rdf-schema#comment",
object: {
value: "Defines the node as a Person (from foaf)",
},
},
],
},
{
type: "TripleConstraint",
predicate: "http://www.w3.org/2006/vcard/ns#fn",
valueExpr: {
type: "NodeConstraint",
datatype: "http://www.w3.org/2001/XMLSchema#string",
},
min: 0,
max: 1,
annotations: [
{
type: "Annotation",
predicate: "http://www.w3.org/2000/01/rdf-schema#comment",
object: {
value:
"The formatted name of a person. Example: John Smith",
},
},
],
},
{
type: "TripleConstraint",
predicate: "http://www.w3.org/2006/vcard/ns#hasEmail",
valueExpr: {
type: "NodeConstraint",
datatype: "http://www.w3.org/2001/XMLSchema#string",
},
min: 0,
max: 1,
annotations: [
{
type: "Annotation",
predicate: "http://www.w3.org/2000/01/rdf-schema#comment",
object: {
value: "The person's email.",
},
},
],
},
],
},
extra: ["http://www.w3.org/1999/02/22-rdf-syntax-ns#type"],
},
},
],
};

@ -0,0 +1,19 @@
import { ShapeType } from "@ldo/ldo";
import { contactSchema } from "./contact.schema";
import { contactContext } from "./contact.context";
import { NGSocialContact } from "./contact.typings";
/**
* =============================================================================
* LDO ShapeTypes contact
* =============================================================================
*/
/**
* NGSocialContact ShapeType
*/
export const NGSocialContactShapeType: ShapeType<NGSocialContact> = {
schema: contactSchema,
shape: "did:ng:n:g:x:social:contact#NGSocialContact",
context: contactContext,
};

@ -0,0 +1,37 @@
import { LdoJsonldContext, LdSet } from "@ldo/ldo";
/**
* =============================================================================
* Typescript Typings for contact
* =============================================================================
*/
/**
* NGSocialContact Type
*/
export interface NGSocialContact {
"@id"?: string;
"@context"?: LdoJsonldContext;
/**
* Defines the node as an Individual (from vcard) | Defines the node as a Person (from Schema.org) | Defines the node as a Person (from foaf)
*/
type: LdSet<
| {
"@id": "Individual";
}
| {
"@id": "Person";
}
| {
"@id": "Person2";
}
>;
/**
* The formatted name of a person. Example: John Smith
*/
fn?: string;
/**
* The person's email.
*/
hasEmail?: string;
}

@ -0,0 +1,26 @@
# Platform ontologies:
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX owl: <http://www.w3.org/2002/07/owl#>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
PREFIX dc: <http://purl.org/dc/terms/>
# Domain ontology for Contacts in vcard-like form
PREFIX vcard: <http://www.w3.org/2006/vcard/ns#>
PREFIX schem: <http://schema.org/>
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
PREFIX ngx: <did:ng:n:g:x:social:contact#>
ngx:NGSocialContact EXTRA a {
a [vcard:Individual ]
// rdfs:comment "Defines the node as an Individual (from vcard)" ;
a [ schem:Person ]
// rdfs:comment "Defines the node as a Person (from Schema.org)" ;
a [ foaf:Person ]
// rdfs:comment "Defines the node as a Person (from foaf)" ;
vcard:fn xsd:string ?
// rdfs:comment "The formatted name of a person. Example: John Smith" ;
vcard:hasEmail xsd:string ?
// rdfs:comment "The person's email." ;
}

@ -1 +1,56 @@
.centered {
/*max-width: 1280px;*/
margin: 0 auto;
padding: 0rem;
text-align: center;
width: fit-content;
}
.contact {
width: 300px;
height: 100px;
background-color: #f6f6f6;
position: relative;
overflow-wrap: anywhere;
}
.name {
width: 300px;
position: absolute;
left: 0;
top: 0;
padding: 5px;
height: 35px;
overflow: hidden;
background-color: #e0e0e0d0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.email-logo {
position: absolute;
left: 5px;
top: 35px;
}
.email {
width: 270px;
position: absolute;
left: 30px;
top: 30px;
padding: 5px;
overflow-wrap: anywhere;
}
input {
margin: 5px;
}
#save {
background-color:rgb(73, 114, 165);
color:white;
cursor:pointer;
}

@ -1,34 +1,19 @@
import { useState } from 'react'
import React, { FunctionComponent } from 'react';
import { Header } from './Header';
import { Contact } from './Contact';
import { BrowserNGLdoProvider, useNextGraphAuth } from './reactMethods';
import { Contacts } from './Contacts';
import { BrowserNGLdoProvider } from './reactMethods';
import './App.css'
import "../../../common/src/styles.css";
// function App() {
// const [count, setCount] = useState(0)
// return (
// <div className="flex flex-col items-center justify-center h-screen bg-gray-100">
// <h1 className="text-4xl font-bold text-blue-600">Hello, Tailwind!</h1>
// <p className="mt-4 text-gray-700">Tailwind CSS is working in Vite!</p>
// </div>
// )
// }
const App: FunctionComponent = () => {
//const { session } = useNextGraphAuth();
return (
<div className="App">
<BrowserNGLdoProvider>
<Header />
<Contact />
<Contacts />
</BrowserNGLdoProvider>
</div>
);

@ -1,22 +1,29 @@
import { FunctionComponent } from "react";
import { useNextGraphAuth } from "./reactMethods";
import { ContainerShapeType } from "./.ldo/container.shapeTypes.ts";
import { NGSocialContactShapeType } from "./.ldo/contact.shapeTypes.ts";
import { useSubscribeToResource, useResource, useSubject } from "./reactMethods.ts";
export const Contact: FunctionComponent = () => {
export const Contact: FunctionComponent = ({nuri}) => {
const { session } = useNextGraphAuth();
let container_overlay;
useResource(session.sessionId ? "did:ng:"+session.privateStoreId : undefined);
let myContainer = useSubject(ContainerShapeType, session.sessionId ? "did:ng:"+(session.privateStoreId.substring(0,46)) : undefined);
if (session.sessionId) {
container_overlay = session.privateStoreId.substring(46);
console.log(container_overlay);
}
if (!session.sessionId) return <></>;
useResource(session.sessionId && nuri ? nuri : undefined, { subscribe: true });
let contact = useSubject(NGSocialContactShapeType, session.sessionId && nuri ? nuri.substring(0,53) : undefined);
if (!session.sessionId || !nuri) return <></>;
return <>{myContainer.contains?.map((contained) => <p className="mb-5" style={{overflowWrap:"anywhere"}} key={contained["@id"]}>{contained["@id"]}</p>)}</>;
return <>
{contact.fn? (
<div
className="contact"
>
<span className="name"> {contact.fn}
</span>
<svg className="w-6 h-6 inline email-logo" data-slot="icon" fill="none" strokeWidth="1.5" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
<path strokeLinecap="round" strokeLinejoin="round" d="M16.5 12a4.5 4.5 0 1 1-9 0 4.5 4.5 0 0 1 9 0Zm0 0c0 1.657 1.007 3 2.25 3S21 13.657 21 12a9 9 0 1 0-2.636 6.364M16.5 12V8.25"></path>
</svg>
<span className="email text-left"> email:&nbsp;{contact.hasEmail}
</span>
</div>
) : <></>}
</>;
};

@ -0,0 +1,40 @@
import { FunctionComponent } from "react";
import { useNextGraphAuth } from "./reactMethods";
import { ContainerShapeType } from "./.ldo/container.shapeTypes.ts";
import { useSubscribeToResource, useResource, useSubject } from "./reactMethods.ts";
import { Contact } from "./Contact";
import { MakeContact } from "./MakeContact";
export const Contacts: FunctionComponent = () => {
const { session } = useNextGraphAuth();
let container_overlay: string;
useResource(session.sessionId ? "did:ng:"+session.privateStoreId : undefined, { subscribe: true });
let myContainer = useSubject(ContainerShapeType, session.sessionId ? "did:ng:"+(session.privateStoreId.substring(0,46)) : undefined);
if (session.sessionId) {
container_overlay = session.privateStoreId.substring(46) as string;
}
if (!session.sessionId) return <></>;
return <>
<div className="centered">
<div className="flex flex-wrap justify-center gap-5 mb-10">
<MakeContact/>
</div>
<div className="flex flex-wrap justify-center gap-5 mb-10">
{
myContainer.contains?.map((contained) =>
<Contact key={contained["@id"]} nuri={contained["@id"]+container_overlay}/>
)}
</div>
</div>
</>;
};

@ -1,13 +1,39 @@
import { FormEvent, FunctionComponent, useCallback, useState } from "react";
import { BrowserNGLdoProvider, useLdo, dataset } from './reactMethods';
import { NGSocialContactShapeType } from "./.ldo/contact.shapeTypes.ts";
import { LdSet } from "@ldo/ldo";
export const MakePost: FunctionComponent = () => {
export const MakeContact: FunctionComponent = () => {
const [name, setName] = useState("");
const [email, setEmail] = useState("");
const { createData, commitData } = useLdo();
const onSubmit = useCallback(
async (e: FormEvent<HTMLFormElement>) => {
e.preventDefault();
if (name.trim().length > 2 && email.trim().length > 6 && email.indexOf("@") >= 0) {
const resource = await dataset.createResource("nextgraph");
if (!resource.isError) {
console.log("Created resource:", resource.uri);
const contact = createData(
NGSocialContactShapeType,
resource.uri.substring(0,53),
resource
);
contact.type = { "@id": "Individual" };
contact.fn = name.trim();
contact.hasEmail = email.trim();
const result = await commitData(contact);
if (result.isError) {
console.error(result.message);
}
}
}
},
[name, email]
);
@ -26,7 +52,7 @@ export const MakePost: FunctionComponent = () => {
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
<input type="submit" value="Post" />
<input type="submit" id="save" value="Save" />
</form>
);
};
Loading…
Cancel
Save