The @web-of-trust/ui
package offers a collection of versatile and reusable React components designed to facilitate the display and management of credential claims within your applications. Built with Material-UI (MUI) for consistent styling and seamless integration, these components support features like authentication, evidence presentation, and interactive comments.
- ClaimCard Component: Display and manage credential claims with support for authentication, evidence, and comments.
- Responsive Design: Ensures components adapt seamlessly across various devices and screen sizes.
- Theme Customization: Easily extend and customize the Material-UI theme to match your application's branding.
- TypeScript Support: Fully typed components for enhanced developer experience and type safety.
- Image Handling: Support for displaying images within achievements and portfolio items.
Ensure you have Node.js (>=16) installed.
Install the package via npm:
npm install @web-of-trust/ui
Or using yarn:
yarn add @web-of-trust/ui
To rapidly set up a demo project showcasing the @web-of-trust/ui
components, use the create-wot-app
CLI tool. This tool automates the creation of a modern React-based development environment, complete with Webpack, TypeScript, and Material-UI.
You can run the CLI tool directly via npx
:
npx create-wot-app
-
Run the CLI Tool
npx create-wot-app
-
Follow the Prompts
The CLI will prompt you for the project name and other configurations.
-
Navigate to the Project Directory
cd your-project-name
-
Start the Development Server
npm run dev
or
yarn dev
-
View the Demo
Open http://localhost:3000 in your browser to see the demo project in action, featuring the
@web-of-trust/ui
components.
To leverage the ClaimCard
component and other UI components effectively, extend the Material-UI theme with custom palette properties.
import { createTheme } from '@mui/material/styles';
// Extend theme declaration
declare module '@mui/material/styles' {
interface Palette {
t3BodyText: string;
bgCredentialDetails: string;
}
interface PaletteOptions {
t3BodyText?: string;
bgCredentialDetails?: string;
}
}
// Create theme with required properties
const theme = createTheme({
palette: {
primary: {
main: '#003FE0', // Default primary color
},
t3BodyText: '#202e5b', // Text color for specific elements
bgCredentialDetails: '#C2F1BE', // Background for credential detail indicators
},
});
Wrap your application with ThemeProvider
to apply the custom theme:
import { ThemeProvider } from '@mui/material/styles';
import { theme } from './lib/theme';
import { ClaimCard } from '@web-of-trust/ui';
function App() {
return (
<ThemeProvider theme={theme}>
<ClaimCard
claimDetail={claimDetail}
status="authenticated"
/>
</ThemeProvider>
);
}
If you do not use the ThemeProvider
:
- Default Material-UI theme will be applied.
- Custom palette properties (
t3BodyText
,bgCredentialDetails
) will be undefined. - Components may have inconsistent styling.
- Some color-specific styles might fall back to hardcoded values.
The ClaimCard
component is a versatile React component for displaying and managing credential claims with support for authentication, evidence, and comments.
interface ClaimCardProps {
onAchievementLoad?: (achievementName: string) => void;
claimDetail: ClaimDetail | null;
status: 'loading' | 'authenticated' | 'unauthenticated';
comments?: ClaimDetail[];
errorMessage?: string | null;
loading?: boolean;
}
onAchievementLoad
: Optional callback triggered when an achievement is loaded.claimDetail
: Credential claim details.status
: Authentication status; can be'loading'
,'authenticated'
, or'unauthenticated'
.comments
: Optional array of comment details.errorMessage
: Optional error message string.loading
: Optional loading state indicator.
-
Loading State:
- Displays a circular progress indicator.
- Triggered when
status === 'loading'
orloading
istrue
.
-
Unauthenticated State:
- Shows a sign-in message.
- Displays app verification information.
-
Error State:
- Shows an error message when
errorMessage
is present.
- Shows an error message when
-
Authenticated State:
- Displays credential details, achievements, portfolio, and comments.
- Dynamic rendering based on authentication status.
- Detailed achievement display.
- Portfolio and evidence link handling.
- Expandable comments section.
- Responsive Material-UI design.
Here's how to use the ClaimCard
component in your application:
import React, { useState } from 'react';
import { ClaimCard } from '@web-of-trust/ui';
import { ClaimDetail } from '@web-of-trust/ui';
import { ThemeProvider, createTheme } from '@mui/material/styles';
import { useSession } from 'next-auth/react';
import { ClaimDetail } from '@web-of-trust/ui'; // Assuming types are exported
const theme = createTheme({
palette: {
t3BodyText: '#202e5b',
bgCredentialDetails: '#C2F1BE',
},
});
const mockClaimDetail: ClaimDetail = {
'@context': [
'https://www.w3.org/2018/credentials/v1',
'https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.3.json',
],
id: 'urn:uuid:123',
type: ['VerifiableCredential', 'OpenBadgeCredential'],
issuer: {
id: 'did:key:example',
type: ['Profile'],
},
issuanceDate: '2024-12-27T17:43:58.457Z',
expirationDate: '2025-12-27T17:43:58.455Z',
credentialSubject: {
type: ['AchievementSubject'],
name: 'John Doe',
duration: '3 months',
achievement: [
{
id: 'urn:uuid:leadership-achievement',
type: ['Achievement'],
name: 'Leadership Excellence',
description: 'Demonstrated exceptional leadership skills',
criteria: {
narrative: 'Led multiple successful team projects',
},
},
],
portfolio: [
{
'@type': 'schema:CreativeWork',
name: 'Project Documentation',
url: 'https://example.com/doc',
},
],
evidenceLink: '',
evidenceDescription:
'Describe how you earned this skill to test the text wrapping',
credentialType: '',
},
proof: {
type: 'Ed25519Signature2020',
created: '2024-12-27T17:43:58Z',
verificationMethod: 'did:key:example',
proofPurpose: 'assertionMethod',
proofValue: 'example-proof-value',
},
};
const mockComments: ClaimDetail[] = [
{
'@context': [
'https://www.w3.org/2018/credentials/v1',
'https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.3.json',
],
id: 'comment1',
type: ['VerifiableCredential', 'OpenBadgeCredential'],
issuer: {
id: 'did:key:commenter',
type: ['Profile'],
},
issuanceDate: '2024-12-27T17:43:58.457Z',
expirationDate: '2025-12-27T17:43:58.455Z',
credentialSubject: {
name: 'Jane Smith',
howKnow: 'Worked together for 2 years',
recommendationText: 'Excellent team player and leader',
qualifications: 'Senior Manager',
explainAnswer: 'Witnessed leadership abilities firsthand',
},
proof: {
type: 'Ed25519Signature2020',
created: '2024-12-27T17:43:58Z',
verificationMethod: 'did:key:commenter',
proofPurpose: 'assertionMethod',
proofValue: 'example-comment-proof-value',
},
},
];
function CredentialView() {
const [claimDetail, setClaimDetail] = useState<ClaimDetail | null>(mockClaimDetail);
const [comments, setComments] = useState<ClaimDetail[]>(mockComments);
const [loading, setLoading] = useState<boolean>(false);
const [errorMessage, setErrorMessage] = useState<string | null>(null);
const { data: session, status } = useSession();
return (
<ThemeProvider theme={theme}>
<ClaimCard
claimDetail={claimDetail}
status={status as 'loading' | 'authenticated' | 'unauthenticated'}
comments={comments}
errorMessage={errorMessage}
loading={loading}
/>
</ThemeProvider>
);
}
export default CredentialView;
export interface Portfolio {
'@type'?: string;
name: string;
url: string;
}
export interface AchievementImage {
id: string;
type?: string;
}
export interface Achievement {
id?: string;
type?: string[];
name: string;
description?: string;
criteria?: {
narrative?: string;
};
image?: AchievementImage;
}
export interface CredentialSubject {
type?: string[];
name: string;
portfolio?: Portfolio[];
duration?: string;
createdTime?: string;
evidenceLink?: string;
evidenceDescription?: string;
howKnow?: string;
recommendationText?: string;
qualifications?: string;
explainAnswer?: string;
credentialType?: string;
achievement?: Achievement[];
}
export interface ClaimDetail {
'@context': (string | { [key: string]: string })[];
id: string;
type: string[];
issuer?: {
id: string;
type?: string[];
};
issuanceDate: string;
expirationDate: string;
credentialSubject: CredentialSubject;
proof?: {
type: string;
created: string;
verificationMethod: string;
proofPurpose: string;
proofValue: string;
};
}
const exampleClaim: ClaimDetail = {
'@context': [
'https://www.w3.org/2018/credentials/v1',
'https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.3.json',
],
id: 'urn:uuid:123',
type: ['VerifiableCredential', 'OpenBadgeCredential'],
issuer: {
id: 'did:key:example',
type: ['Profile'],
},
issuanceDate: '2024-12-27T17:43:58.457Z',
expirationDate: '2025-12-27T17:43:58.455Z',
credentialSubject: {
type: ['AchievementSubject'],
name: 'John Doe',
duration: '3 months',
achievement: [
{
id: 'urn:uuid:leadership-achievement',
type: ['Achievement'],
name: 'Leadership Excellence',
description: 'Demonstrated exceptional leadership skills',
criteria: {
narrative: 'Led multiple successful team projects',
},
},
],
portfolio: [
{
'@type': 'schema:CreativeWork',
name: 'Project Documentation',
url: 'https://example.com/doc',
},
],
evidenceLink: '',
evidenceDescription:
'Describe how you earned this skill to test the text wrapping',
credentialType: '',
},
proof: {
type: 'Ed25519Signature2020',
created: '2024-12-27T17:43:58Z',
verificationMethod: 'did:key:example',
proofPurpose: 'assertionMethod',
proofValue: 'example-proof-value',
},
};
const exampleClaimWithImage: ClaimDetail = {
'@context': [
'https://www.w3.org/2018/credentials/v1',
'https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.3.json',
{
duration: 'https://schema.org/duration',
fullName: 'https://schema.org/name',
portfolio: 'https://schema.org/portfolio',
evidenceLink: 'https://schema.org/evidenceLink',
evidenceDescription: 'https://schema.org/evidenceDescription',
credentialType: 'https://schema.org/credentialType',
},
'https://w3id.org/security/suites/ed25519-2020/v1',
],
id: 'urn:uuid:456',
type: ['VerifiableCredential', 'OpenBadgeCredential'],
issuer: {
id: 'did:key:example2',
type: ['Profile'],
},
issuanceDate: '2025-01-08T18:09:45.621Z',
expirationDate: '2026-01-08T18:09:45.615Z',
credentialSubject: {
type: ['AchievementSubject'],
name: 'Jane Smith',
duration: '5 years',
achievement: [
{
id: 'urn:uuid:software-dev-achievement',
type: ['Achievement'],
name: 'Software Development',
description: 'Developed comprehensive software solutions',
criteria: {
narrative: 'Contributed to multiple software projects',
},
image: {
id: 'https://placehold.co/600x400',
type: 'Image',
},
},
],
portfolio: [
{
'@type': 'schema:CreativeWork',
name: 'Project Portfolio',
url: 'https://example.com/portfolio',
},
],
evidenceLink: 'https://placehold.co/600x400',
credentialType: 'Software Engineering',
},
proof: {
type: 'Ed25519Signature2020',
created: '2025-01-08T18:09:45Z',
verificationMethod: 'did:key:example2',
proofPurpose: 'assertionMethod',
proofValue: 'example-proof-value-2',
},
};
const mockComments: ClaimDetail[] = [
{
'@context': [
'https://www.w3.org/2018/credentials/v1',
'https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.3.json',
],
id: 'comment1',
type: ['VerifiableCredential', 'OpenBadgeCredential'],
issuer: {
id: 'did:key:commenter',
type: ['Profile'],
},
issuanceDate: '2024-12-27T17:43:58.457Z',
expirationDate: '2025-12-27T17:43:58.455Z',
credentialSubject: {
name: 'Jane Smith',
howKnow: 'Worked together for 2 years',
recommendationText: 'Excellent team player and leader',
qualifications: 'Senior Manager',
explainAnswer: 'Witnessed leadership abilities firsthand',
},
proof: {
type: 'Ed25519Signature2020',
created: '2024-12-27T17:43:58Z',
verificationMethod: 'did:key:commenter',
proofPurpose: 'assertionMethod',
proofValue: 'example-comment-proof-value',
},
},
];
This project is licensed under the ISC License.