Concept
Enable rich inline previews of Solid resources when pasted in chat. Instead of just showing a link, detect the RDF type and render it using the appropriate SolidOS pane.
Example Use Cases
Sharing a contact:
Alice: Check out this person @https://bob.pod/profile/card#me
→ Renders inline contact card with name, photo, email
Sharing a meeting:
Bob: Join standup @https://team.pod/meetings/daily.ttl#this
→ Renders meeting details, time, participants, join button
Sharing a task:
Charlie: Can you review @https://project.pod/tasks/feature-x#task1
→ Renders task card with status, assignee, deadline
Sharing a document:
Dave: See the spec @https://docs.pod/specs/api-v2.ttl#this
→ Renders document preview with title, author, last modified
How It Works with mashlib
mashlib Pane System
SolidOS/mashlib has a pane registry where panes register what RDF types they can handle:
// Example: contact pane registration{icon: 'https://solid.github.io/solid-ui/src/icons/noun_99101.svg',name: 'contact',label: (subject,context)=>'Contact',// What types this pane handlesmintClass: ns.vcard('Individual'),// Can it render this resource?shouldRender: (subject,context)=>{consttypes=context.session.store.findTypeURIs(subject)returntypes['http://www.w3.org/2006/vcard/ns#Individual']},// Render functionrender: (subject,context)=>{constdiv=context.dom.createElement('div')// ... render contact cardreturndiv}}Dynamic Pane Registration
Panes are registered in mashlib's panes/index.js:
import{contactPane}from'./contact/contactPane'import{schedulePane}from'./schedule/schedulePane'import{issuePane}from'./issue/issuePane'exportconstpanes={list: [contactPane,schedulePane,issuePane, ...],byName: (name)=>panes.list.find(p=>p.name===name),byType: (type)=>panes.list.find(p=>p.mintClass?.uri===type)}Implementation Approach
Option 1: Import mashlib (Full Integration)
import{panes}from'mashlib'asyncfunctionrenderSolidResource(uri,dom,context){// 1. Fetch resourceconstsubject=$rdf.sym(uri)awaitstore.fetcher.load(subject.doc())// 2. Get RDF typesconsttypes=store.each(subject,RDF('type'))// 3. Find matching panefor(consttypeoftypes){constpane=panes.byType(type.value)if(pane&&pane.shouldRender(subject,context)){// 4. Render with panereturnpane.render(subject,context)}}// 5. Fallback: generic RDF viewerreturnrenderGenericRDF(subject,dom,context)}Pros:
- Full SolidOS ecosystem integration
- Access to all existing panes
- Automatic updates when panes are added
Cons:
- Heavy dependency (mashlib is large)
- May pull in unnecessary UI code
Option 2: Minimal Pane Registry (Lightweight)
// Define minimal pane interfaceconstminiPanes={contact: {type: 'http://www.w3.org/2006/vcard/ns#Individual',render: async(subject,store,dom)=>{constname=store.any(subject,VCARD('fn'))constphoto=store.any(subject,VCARD('hasPhoto'))constcard=dom.createElement('div')card.className='contact-preview'if(photo)card.innerHTML=`<img src="${photo.value}" />`card.innerHTML+=`<h3>${name?.value||'Unknown'}</h3>`returncard}},meeting: {type: 'http://www.w3.org/ns/pim/meeting#Meeting',render: async(subject,store,dom)=>{// ... render meeting}}}// Use itasyncfunctionrenderResource(uri){constsubject=$rdf.sym(uri)awaitstore.fetcher.load(subject.doc())consttypes=store.each(subject,RDF('type'))for(consttypeoftypes){constpane=Object.values(miniPanes).find(p=>p.type===type.value)if(pane)returnpane.render(subject,store,dom)}returnnull// No pane found}Pros:
- Lightweight
- Full control
- Easy to add custom renderers
Cons:
- Manual maintenance
- Limited to types we implement
- Doesn't leverage SolidOS ecosystem
Option 3: Hybrid (Recommended)
// 1. Try mashlib panes first (if available)letrendered=nullif(window.mashlib){constpane=mashlib.panes.byType(type)if(pane)rendered=pane.render(subject,context)}// 2. Fallback to mini registryif(!rendered){constminiPane=miniPanes[type]if(miniPane)rendered=miniPane.render(subject,store,dom)}// 3. Final fallback: generic link previewif(!rendered){rendered=renderGenericPreview(subject,store,dom)}Pros:
- Best of both worlds
- Works standalone or with mashlib
- Progressive enhancement
Message Content Parsing
Detect Solid URIs
functionrenderMessageContent(dom,content){constcontainer=dom.createElement('div')consttokens=[]letlastIndex=0// Match Solid URIs (ending in .ttl or #fragment)constSOLID_URI=/(https?:\/\/[^\s]+(?:\.ttl|#\w+))/gcontent.replace(SOLID_URI,(match,uri,index)=>{if(index>lastIndex){tokens.push({type: 'text',value: content.slice(lastIndex,index)})}tokens.push({type: 'solid-resource', uri })lastIndex=index+match.length})// Render tokensfor(consttokenoftokens){if(token.type==='solid-resource'){constpreview=awaitrenderSolidResource(token.uri,dom,context)container.appendChild(preview)}else{container.appendChild(dom.createTextNode(token.value))}}returncontainer}Async Loading
// Show placeholder while loadingconstplaceholder=dom.createElement('div')placeholder.className='resource-loading'placeholder.textContent=`Loading ${uri}...`container.appendChild(placeholder)// Load and renderrenderSolidResource(uri,dom,context).then(preview=>{placeholder.replaceWith(preview)}).catch(err=>{placeholder.textContent=`Error loading resource: ${err.message}`})UI Design
Inline Preview Card
.resource-preview {
border:1px solid #e1e4e8;
border-radius:6px;
padding:16px;
margin:12px0;
background:linear-gradient(135deg,#667eea0%,#764ba2100%);
background: white;
box-shadow:01px3pxrgba(0,0,0,0.12);
max-width:400px;
transition: box-shadow 0.2s;
}
.resource-preview:hover {
box-shadow:04px12pxrgba(0,0,0,0.15);
}
.resource-preview-header {
display: flex;
align-items: center;
gap:8px;
margin-bottom:12px;
padding-bottom:12px;
border-bottom:1px solid #e1e4e8;
}
.resource-preview-icon {
width:20px;
height:20px;
opacity:0.8;
}
.resource-preview-type {
font-size:11px;
text-transform: uppercase;
letter-spacing:0.5px;
color:#6a737d;
font-weight:600;
}
.resource-preview-content {
/* Pane-specific content */
}
.resource-preview-link {
display: inline-block;
margin-top:12px;
font-size:13px;
color:#0366d6;
text-decoration: none;
font-weight:500;
}
.resource-preview-link:hover {
text-decoration: underline;
}Example Rendered Cards
Contact Card
Meeting Card
📅 MEETING
Daily Standup
🕐 Today at 10:00 AM
👥 3 participants Join Meeting · View details → |
Document Card
📄 DOCUMENT
API Specification v2.0
✍️ Alice Johnson
🕒 Updated 2 hours ago Read document → |
Common Types to Support
| RDF Type | Pane | Example |
|---|
vcard:Individual | contact-pane | Person profiles |
meeting:Meeting | schedule-pane | Meetings, events |
schema:ImageObject | image-pane | Photos (already works) |
foaf:Document | document-pane | Documents, notes |
ui:Form | form-pane | Interactive forms |
issue:Issue | issue-pane | Bug reports, tasks |
cal:Event | schedule-pane | Calendar events |
Benefits
1. Semantic Rich Previews
- Not just links, but meaningful data
- Context-aware rendering
- Interactive widgets
2. SolidOS Ecosystem Integration
- Leverage existing panes
- Consistent UI across apps
- Community-maintained renderers
3. Extensibility
- Easy to add new types
- Custom panes for app-specific types
- Plugin architecture
4. Better UX
- Less context switching
- Preview before clicking
- Inline actions (join meeting, add contact, etc.)
Implementation Tasks
References
Related Issues
Concept
Enable rich inline previews of Solid resources when pasted in chat. Instead of just showing a link, detect the RDF type and render it using the appropriate SolidOS pane.
Example Use Cases
Sharing a contact:
→ Renders inline contact card with name, photo, email
Sharing a meeting:
→ Renders meeting details, time, participants, join button
Sharing a task:
→ Renders task card with status, assignee, deadline
Sharing a document:
→ Renders document preview with title, author, last modified
How It Works with mashlib
mashlib Pane System
SolidOS/mashlib has a pane registry where panes register what RDF types they can handle:
Dynamic Pane Registration
Panes are registered in mashlib's
panes/index.js:Implementation Approach
Option 1: Import mashlib (Full Integration)
Pros:
Cons:
Option 2: Minimal Pane Registry (Lightweight)
Pros:
Cons:
Option 3: Hybrid (Recommended)
Pros:
Message Content Parsing
Detect Solid URIs
Async Loading
UI Design
Inline Preview Card
Example Rendered Cards
Contact Card
👤 CONTACT
🧑💼 Bob Smith
📧 bob@example.com
📱 +1-555-0123
View full profile →
Meeting Card
📅 MEETING
Daily Standup
🕐 Today at 10:00 AM
👥 3 participants
Join Meeting · View details →
Document Card
📄 DOCUMENT
API Specification v2.0
✍️ Alice Johnson
🕒 Updated 2 hours ago
Read document →
Common Types to Support
vcard:Individualmeeting:Meetingschema:ImageObjectfoaf:Documentui:Formissue:Issuecal:EventBenefits
1. Semantic Rich Previews
2. SolidOS Ecosystem Integration
3. Extensibility
4. Better UX
Implementation Tasks
References
Related Issues