Basic Live Pages Examples
Overview
This page contains simple, easy-to-understand examples to help you get started with Live Pages. Each example focuses on one core concept and can be implemented quickly.
Simple Task List
The most basic Live Page - a task list with add and delete functionality:
<div class="container mx-auto p-6 max-w-2xl">
<h1 class="text-2xl font-bold mb-4">My Tasks</h1>
<div class="flex gap-2 mb-4">
<input
type="text"
id="taskInput"
class="flex-1 px-3 py-2 border rounded"
placeholder="New task..."
>
<button
onclick="addTask()"
class="bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600"
>
Add
</button>
</div>
<div id="tasksList"></div>
</div>
<script>
async function loadTasks() {
const entities = await pt.list({
entityNames: ['task'],
filters: { completed: false }
});
const tasks = entities.filter(e => e.entity_name === 'task');
document.getElementById('tasksList').innerHTML = tasks.map(task => `
<div class="bg-white p-4 rounded shadow mb-2 flex justify-between items-center">
<span>${task.data.text}</span>
<button onclick="deleteTask(${task.id})" class="text-red-500 hover:text-red-700">
Delete
</button>
</div>
`).join('');
}
async function addTask() {
const text = document.getElementById('taskInput').value.trim();
if (!text) return;
await pt.add('task', {
text: text,
completed: false
});
document.getElementById('taskInput').value = '';
await loadTasks();
}
async function deleteTask(taskId) {
await pt.delete(taskId);
await loadTasks();
}
// Load tasks when page loads
document.addEventListener('DOMContentLoaded', loadTasks);
</script>
Task List with Completion Toggle
Add checkbox functionality to mark tasks as complete:
<div class="container mx-auto p-6 max-w-2xl">
<h1 class="text-2xl font-bold mb-4">My Tasks</h1>
<div class="flex gap-2 mb-4">
<input
type="text"
id="taskInput"
class="flex-1 px-3 py-2 border rounded"
placeholder="New task..."
>
<button
onclick="addTask()"
class="bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600"
>
Add
</button>
</div>
<div id="tasksList"></div>
</div>
<script>
async function loadTasks() {
const entities = await pt.list({
entityNames: ['task']
});
const tasks = entities.filter(e => e.entity_name === 'task');
document.getElementById('tasksList').innerHTML = tasks.map(task => {
const isCompleted = task.data.completed === true;
return `
<div class="bg-white p-4 rounded shadow mb-2 flex justify-between items-center ${isCompleted ? 'opacity-50' : ''}">
<div class="flex items-center gap-3">
<input
type="checkbox"
${isCompleted ? 'checked' : ''}
onchange="toggleTask(${task.id})"
class="h-4 w-4"
>
<span class="${isCompleted ? 'line-through text-gray-500' : ''}">
${task.data.text}
</span>
</div>
<button onclick="deleteTask(${task.id})" class="text-red-500 hover:text-red-700">
Delete
</button>
</div>
`;
}).join('');
}
async function addTask() {
const text = document.getElementById('taskInput').value.trim();
if (!text) return;
await pt.add('task', {
text: text,
completed: false
});
document.getElementById('taskInput').value = '';
await loadTasks();
}
async function toggleTask(taskId) {
const task = await pt.get(taskId);
await pt.edit(taskId, {
...task.data,
completed: !task.data.completed
});
await loadTasks();
}
async function deleteTask(taskId) {
await pt.delete(taskId);
await loadTasks();
}
document.addEventListener('DOMContentLoaded', loadTasks);
</script>
Simple Search
Add search functionality to filter tasks:
<div class="container mx-auto p-6 max-w-2xl">
<h1 class="text-2xl font-bold mb-4">My Tasks</h1>
<!-- Search Input -->
<input
type="text"
id="searchInput"
class="w-full px-3 py-2 border rounded mb-4"
placeholder="Search tasks..."
>
<!-- Add Task -->
<div class="flex gap-2 mb-4">
<input
type="text"
id="taskInput"
class="flex-1 px-3 py-2 border rounded"
placeholder="New task..."
>
<button
onclick="addTask()"
class="bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600"
>
Add
</button>
</div>
<div id="tasksList"></div>
</div>
<script>
let searchTimeout;
async function loadTasks() {
const searchTerm = document.getElementById('searchInput').value.trim();
const filters = {};
if (searchTerm) {
filters.text = { $contains: searchTerm };
}
const entities = await pt.list({
entityNames: ['task'],
filters: filters
});
const tasks = entities.filter(e => e.entity_name === 'task');
if (tasks.length === 0) {
document.getElementById('tasksList').innerHTML = `
<div class="text-center py-8 text-gray-500">
No tasks found
</div>
`;
return;
}
document.getElementById('tasksList').innerHTML = tasks.map(task => `
<div class="bg-white p-4 rounded shadow mb-2 flex justify-between items-center">
<span>${task.data.text}</span>
<button onclick="deleteTask(${task.id})" class="text-red-500 hover:text-red-700">
Delete
</button>
</div>
`).join('');
}
async function addTask() {
const text = document.getElementById('taskInput').value.trim();
if (!text) return;
await pt.add('task', {
text: text,
completed: false
});
document.getElementById('taskInput').value = '';
await loadTasks();
}
async function deleteTask(taskId) {
await pt.delete(taskId);
await loadTasks();
}
// Setup search with debouncing
document.getElementById('searchInput').addEventListener('input', () => {
clearTimeout(searchTimeout);
searchTimeout = setTimeout(loadTasks, 300);
});
document.addEventListener('DOMContentLoaded', loadTasks);
</script>
Task List with Priority
Add priority levels to tasks:
<div class="container mx-auto p-6 max-w-2xl">
<h1 class="text-2xl font-bold mb-4">My Tasks</h1>
<!-- Add Task with Priority -->
<div class="flex gap-2 mb-4">
<input
type="text"
id="taskInput"
class="flex-1 px-3 py-2 border rounded"
placeholder="New task..."
>
<select id="priorityInput" class="px-3 py-2 border rounded">
<option value="low">Low</option>
<option value="medium">Medium</option>
<option value="high">High</option>
</select>
<button
onclick="addTask()"
class="bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600"
>
Add
</button>
</div>
<div id="tasksList"></div>
</div>
<script>
async function loadTasks() {
const entities = await pt.list({
entityNames: ['task']
});
const tasks = entities.filter(e => e.entity_name === 'task');
document.getElementById('tasksList').innerHTML = tasks.map(task => {
const priorityColors = {
high: 'bg-red-100 text-red-800',
medium: 'bg-yellow-100 text-yellow-800',
low: 'bg-green-100 text-green-800'
};
const priorityClass = priorityColors[task.data.priority] || priorityColors.low;
return `
<div class="bg-white p-4 rounded shadow mb-2 flex justify-between items-center">
<div class="flex items-center gap-3">
<span>${task.data.text}</span>
<span class="px-2 py-1 text-xs rounded-full ${priorityClass}">
${task.data.priority}
</span>
</div>
<button onclick="deleteTask(${task.id})" class="text-red-500 hover:text-red-700">
Delete
</button>
</div>
`;
}).join('');
}
async function addTask() {
const text = document.getElementById('taskInput').value.trim();
const priority = document.getElementById('priorityInput').value;
if (!text) return;
await pt.add('task', {
text: text,
priority: priority,
completed: false
});
document.getElementById('taskInput').value = '';
await loadTasks();
}
async function deleteTask(taskId) {
await pt.delete(taskId);
await loadTasks();
}
document.addEventListener('DOMContentLoaded', loadTasks);
</script>
Simple Counter
A basic counter to demonstrate state management:
<div class="container mx-auto p-6 max-w-md">
<h1 class="text-2xl font-bold mb-4 text-center">Counter</h1>
<div class="bg-white rounded-lg shadow-lg p-8 text-center">
<div class="text-6xl font-bold mb-6" id="counterDisplay">0</div>
<div class="flex gap-2 justify-center">
<button
onclick="decrementCounter()"
class="bg-red-500 text-white px-6 py-3 rounded-lg hover:bg-red-600"
>
-
</button>
<button
onclick="resetCounter()"
class="bg-gray-500 text-white px-6 py-3 rounded-lg hover:bg-gray-600"
>
Reset
</button>
<button
onclick="incrementCounter()"
class="bg-green-500 text-white px-6 py-3 rounded-lg hover:bg-green-600"
>
+
</button>
</div>
</div>
</div>
<script>
let counterId = null;
async function loadCounter() {
const entities = await pt.list({
entityNames: ['counter']
});
if (entities.length === 0) {
// Create initial counter
const result = await pt.add('counter', { value: 0 });
counterId = result.id;
updateDisplay(0);
} else {
const counter = entities[0];
counterId = counter.id;
updateDisplay(counter.data.value);
}
}
function updateDisplay(value) {
document.getElementById('counterDisplay').textContent = value;
}
async function incrementCounter() {
const counter = await pt.get(counterId);
const newValue = counter.data.value + 1;
await pt.edit(counterId, { value: newValue });
updateDisplay(newValue);
}
async function decrementCounter() {
const counter = await pt.get(counterId);
const newValue = counter.data.value - 1;
await pt.edit(counterId, { value: newValue });
updateDisplay(newValue);
}
async function resetCounter() {
await pt.edit(counterId, { value: 0 });
updateDisplay(0);
}
document.addEventListener('DOMContentLoaded', loadCounter);
</script>
Simple Notes List
A minimalist notes application:
<div class="container mx-auto p-6 max-w-2xl">
<h1 class="text-2xl font-bold mb-4">My Notes</h1>
<!-- Add Note -->
<div class="mb-4">
<input
type="text"
id="noteTitleInput"
class="w-full px-3 py-2 border rounded mb-2"
placeholder="Note title..."
>
<textarea
id="noteContentInput"
rows="3"
class="w-full px-3 py-2 border rounded mb-2"
placeholder="Note content..."
></textarea>
<button
onclick="addNote()"
class="bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600"
>
Add Note
</button>
</div>
<!-- Notes List -->
<div id="notesList"></div>
</div>
<script>
async function loadNotes() {
const entities = await pt.list({
entityNames: ['note']
});
const notes = entities.filter(e => e.entity_name === 'note');
if (notes.length === 0) {
document.getElementById('notesList').innerHTML = `
<div class="text-center py-8 text-gray-500">
No notes yet
</div>
`;
return;
}
document.getElementById('notesList').innerHTML = notes.map(note => `
<div class="bg-white rounded-lg shadow p-4 mb-3">
<div class="flex justify-between items-start mb-2">
<h3 class="font-semibold text-lg">${note.data.title}</h3>
<button
onclick="deleteNote(${note.id})"
class="text-red-500 hover:text-red-700"
>
Delete
</button>
</div>
<p class="text-gray-600">${note.data.content}</p>
<div class="text-xs text-gray-400 mt-2">
${new Date(note.created_at).toLocaleDateString()}
</div>
</div>
`).join('');
}
async function addNote() {
const title = document.getElementById('noteTitleInput').value.trim();
const content = document.getElementById('noteContentInput').value.trim();
if (!title || !content) return;
await pt.add('note', {
title: title,
content: content
});
document.getElementById('noteTitleInput').value = '';
document.getElementById('noteContentInput').value = '';
await loadNotes();
}
async function deleteNote(noteId) {
if (confirm('Delete this note?')) {
await pt.delete(noteId);
await loadNotes();
}
}
document.addEventListener('DOMContentLoaded', loadNotes);
</script>
A simple shopping list with quantities:
<div class="container mx-auto p-6 max-w-2xl">
<h1 class="text-2xl font-bold mb-4">Shopping List</h1>
<!-- Add Item -->
<div class="flex gap-2 mb-4">
<input
type="text"
id="itemInput"
class="flex-1 px-3 py-2 border rounded"
placeholder="Item name..."
>
<input
type="number"
id="quantityInput"
value="1"
min="1"
class="w-20 px-3 py-2 border rounded"
>
<button
onclick="addItem()"
class="bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600"
>
Add
</button>
</div>
<!-- Items List -->
<div id="itemsList"></div>
</div>
<script>
async function loadItems() {
const entities = await pt.list({
entityNames: ['shopping_item']
});
const items = entities.filter(e => e.entity_name === 'shopping_item');
if (items.length === 0) {
document.getElementById('itemsList').innerHTML = `
<div class="text-center py-8 text-gray-500">
No items in your shopping list
</div>
`;
return;
}
document.getElementById('itemsList').innerHTML = items.map(item => {
const isPurchased = item.data.purchased === true;
return `
<div class="bg-white p-4 rounded shadow mb-2 flex justify-between items-center ${isPurchased ? 'opacity-50' : ''}">
<div class="flex items-center gap-3">
<input
type="checkbox"
${isPurchased ? 'checked' : ''}
onchange="togglePurchased(${item.id})"
class="h-4 w-4"
>
<span class="${isPurchased ? 'line-through text-gray-500' : ''}">
${item.data.name}
</span>
<span class="text-sm text-gray-600">
(${item.data.quantity})
</span>
</div>
<button
onclick="deleteItem(${item.id})"
class="text-red-500 hover:text-red-700"
>
Delete
</button>
</div>
`;
}).join('');
}
async function addItem() {
const name = document.getElementById('itemInput').value.trim();
const quantity = parseInt(document.getElementById('quantityInput').value);
if (!name) return;
await pt.add('shopping_item', {
name: name,
quantity: quantity,
purchased: false
});
document.getElementById('itemInput').value = '';
document.getElementById('quantityInput').value = '1';
await loadItems();
}
async function togglePurchased(itemId) {
const item = await pt.get(itemId);
await pt.edit(itemId, {
...item.data,
purchased: !item.data.purchased
});
await loadItems();
}
async function deleteItem(itemId) {
await pt.delete(itemId);
await loadItems();
}
document.addEventListener('DOMContentLoaded', loadItems);
</script>
Poll/Voting App
A simple polling application:
<div class="container mx-auto p-6 max-w-2xl">
<h1 class="text-2xl font-bold mb-4">Quick Poll</h1>
<!-- Add Poll Option -->
<div class="bg-white rounded-lg shadow p-4 mb-4">
<input
type="text"
id="optionInput"
class="w-full px-3 py-2 border rounded mb-2"
placeholder="New poll option..."
>
<button
onclick="addOption()"
class="bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600"
>
Add Option
</button>
</div>
<!-- Poll Options -->
<div id="pollOptions"></div>
</div>
<script>
async function loadPoll() {
const entities = await pt.list({
entityNames: ['poll_option']
});
const options = entities.filter(e => e.entity_name === 'poll_option');
if (options.length === 0) {
document.getElementById('pollOptions').innerHTML = `
<div class="text-center py-8 text-gray-500">
No poll options yet. Add one to get started!
</div>
`;
return;
}
// Calculate total votes
const totalVotes = options.reduce((sum, opt) => sum + (opt.data.votes || 0), 0);
document.getElementById('pollOptions').innerHTML = options.map(option => {
const votes = option.data.votes || 0;
const percentage = totalVotes > 0 ? Math.round((votes / totalVotes) * 100) : 0;
return `
<div class="bg-white rounded-lg shadow p-4 mb-3">
<div class="flex justify-between items-center mb-2">
<span class="font-medium">${option.data.text}</span>
<button
onclick="deleteOption(${option.id})"
class="text-red-500 hover:text-red-700 text-sm"
>
Delete
</button>
</div>
<div class="flex items-center gap-3">
<button
onclick="vote(${option.id})"
class="bg-green-500 text-white px-3 py-1 rounded text-sm hover:bg-green-600"
>
Vote
</button>
<div class="flex-1">
<div class="bg-gray-200 rounded-full h-6">
<div
class="bg-blue-500 h-6 rounded-full flex items-center justify-center text-white text-sm"
style="width: ${percentage}%"
>
${percentage > 10 ? percentage + '%' : ''}
</div>
</div>
</div>
<span class="text-sm text-gray-600">${votes} votes</span>
</div>
</div>
`;
}).join('');
}
async function addOption() {
const text = document.getElementById('optionInput').value.trim();
if (!text) return;
await pt.add('poll_option', {
text: text,
votes: 0
});
document.getElementById('optionInput').value = '';
await loadPoll();
}
async function vote(optionId) {
const option = await pt.get(optionId);
await pt.edit(optionId, {
...option.data,
votes: (option.data.votes || 0) + 1
});
await loadPoll();
}
async function deleteOption(optionId) {
if (confirm('Delete this option?')) {
await pt.delete(optionId);
await loadPoll();
}
}
document.addEventListener('DOMContentLoaded', loadPoll);
</script>
Send Message to Chat
Send messages from your Live Page to the chat interface:
<div class="container mx-auto p-6 max-w-2xl">
<h1 class="text-2xl font-bold mb-4">Send Messages</h1>
<div class="flex gap-2 mb-4">
<input
type="text"
id="messageInput"
class="flex-1 px-3 py-2 border rounded"
placeholder="Type a message..."
onkeypress="if(event.key==='Enter') sendMessage()"
>
<button
onclick="sendMessage()"
class="bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600"
>
Send
</button>
</div>
<!-- Quick action buttons -->
<div class="flex gap-2">
<button
onclick="pt.addMessage('Task completed!')"
class="bg-green-500 text-white px-3 py-1 rounded text-sm hover:bg-green-600"
>
Quick: Task Done
</button>
<button
onclick="pt.addMessage('Need help!')"
class="bg-yellow-500 text-white px-3 py-1 rounded text-sm hover:bg-yellow-600"
>
Quick: Need Help
</button>
</div>
</div>
<script>
async function sendMessage() {
const input = document.getElementById('messageInput');
const message = input.value.trim();
if (!message) {
alert('Please enter a message');
return;
}
try {
await pt.addMessage(message);
input.value = '';
alert('Message sent!');
} catch (error) {
alert('Failed to send message: ' + error.message);
}
}
</script>
Upload Files to Chat
Upload files from your Live Page with an optional message:
<div class="container mx-auto p-6 max-w-2xl">
<h1 class="text-2xl font-bold mb-4">Upload Files</h1>
<!-- Simple form upload -->
<form id="uploadForm" onsubmit="handleUpload(event)" class="bg-white rounded-lg shadow p-6">
<div class="mb-4">
<label class="block text-sm font-medium mb-2">Select Files</label>
<input
type="file"
name="files"
multiple
class="block w-full text-sm"
required
>
</div>
<div class="mb-4">
<label class="block text-sm font-medium mb-2">Message (optional)</label>
<input
type="text"
name="message"
placeholder="Add a message..."
class="border rounded px-3 py-2 w-full"
>
</div>
<button
type="submit"
class="bg-green-500 text-white px-4 py-2 rounded hover:bg-green-600"
>
Upload
</button>
</form>
<!-- Drag and drop zone -->
<div
id="dropZone"
ondrop="handleDrop(event)"
ondragover="event.preventDefault()"
class="mt-6 border-2 border-dashed border-gray-300 rounded-lg p-8 text-center"
>
<p class="text-gray-600">Drop files here to upload</p>
</div>
</div>
<script>
async function handleUpload(event) {
event.preventDefault();
const form = event.target;
try {
const result = await pt.uploadFiles(form);
alert(`Uploaded ${result.files_count} file(s) successfully!`);
form.reset();
} catch (error) {
alert('Upload failed: ' + error.message);
}
}
async function handleDrop(event) {
event.preventDefault();
const files = event.dataTransfer.files;
if (files.length === 0) return;
const formData = new FormData();
for (const file of files) {
formData.append('files', file);
}
try {
const result = await pt.uploadFiles(formData, 'Drag & drop upload');
alert(`Uploaded ${result.files_count} file(s)`);
} catch (error) {
alert('Upload failed: ' + error.message);
}
}
</script>
File Upload with Preview
Show file previews before uploading:
<div class="container mx-auto p-6 max-w-2xl">
<h1 class="text-2xl font-bold mb-4">Upload with Preview</h1>
<div class="bg-white rounded-lg shadow p-6">
<input
type="file"
id="fileInput"
multiple
onchange="previewFiles()"
class="mb-4 block w-full"
>
<div id="preview" class="mb-4"></div>
<button
onclick="uploadFiles()"
class="bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600"
>
Upload Selected Files
</button>
</div>
</div>
<script>
function previewFiles() {
const input = document.getElementById('fileInput');
const preview = document.getElementById('preview');
const files = input.files;
if (files.length === 0) {
preview.innerHTML = '';
return;
}
preview.innerHTML = `
<div class="bg-gray-50 p-3 rounded">
<p class="font-medium mb-2">${files.length} file(s) selected:</p>
${Array.from(files).map(file => `
<div class="text-sm text-gray-600">
${file.name} (${(file.size / 1024).toFixed(2)} KB)
</div>
`).join('')}
</div>
`;
}
async function uploadFiles() {
const input = document.getElementById('fileInput');
if (input.files.length === 0) {
alert('Please select files');
return;
}
const formData = new FormData();
for (const file of input.files) {
formData.append('files', file);
}
try {
const result = await pt.uploadFiles(formData, 'Files uploaded from preview');
alert(`Success! Uploaded ${result.files_count} files`);
input.value = '';
document.getElementById('preview').innerHTML = '';
} catch (error) {
alert('Error: ' + error.message);
}
}
</script>
Send Push Notification
Send push notifications to specific users in your chat:
<div class="container mx-auto p-6 max-w-2xl">
<h1 class="text-2xl font-bold mb-4">Send Notification</h1>
<div class="bg-white rounded-lg shadow p-6">
<select id="userSelect" class="border rounded px-3 py-2 w-full mb-3">
<option value="">Select a user...</option>
</select>
<input
type="text"
id="notifTitle"
placeholder="Notification title"
class="border rounded px-3 py-2 w-full mb-3"
>
<textarea
id="notifText"
rows="3"
placeholder="Notification message"
class="border rounded px-3 py-2 w-full mb-3"
></textarea>
<button
onclick="sendNotification()"
class="bg-blue-500 text-white px-4 py-2 rounded w-full hover:bg-blue-600"
>
Send Notification
</button>
</div>
</div>
<script>
// Load users on page load
async function loadUsers() {
const members = await pt.getChatMembers();
const select = document.getElementById('userSelect');
members
.filter(m => m.type === 'user')
.forEach(member => {
const option = document.createElement('option');
option.value = member.id;
option.textContent = member.name;
select.appendChild(option);
});
}
async function sendNotification() {
const userId = parseInt(document.getElementById('userSelect').value);
const title = document.getElementById('notifTitle').value.trim();
const text = document.getElementById('notifText').value.trim();
if (!userId || !title || !text) {
alert('Please fill all fields');
return;
}
try {
await pt.sendNotification(userId, title, text);
alert('Notification sent!');
document.getElementById('notifTitle').value = '';
document.getElementById('notifText').value = '';
} catch (error) {
alert('Error: ' + error.message);
}
}
document.addEventListener('DOMContentLoaded', loadUsers);
</script>
Search Documents
Search across documents and collections using semantic search:
<div class="container mx-auto p-6 max-w-2xl">
<h1 class="text-2xl font-bold mb-4">Document Search</h1>
<div class="bg-white rounded-lg shadow p-6">
<input
type="text"
id="searchQuery"
placeholder="What are you looking for?"
class="border rounded px-3 py-2 w-full mb-3"
>
<select id="searchScope" class="border rounded px-3 py-2 w-full mb-3">
<option value="ALL">All (Documents & Collections)</option>
<option value="DOCUMENTS_ONLY">Documents Only</option>
<option value="COLLECTIONS_ONLY">Collections Only</option>
</select>
<button
onclick="searchDocs()"
class="bg-green-500 text-white px-4 py-2 rounded w-full hover:bg-green-600"
>
Search
</button>
<div id="results" class="mt-4 hidden">
<h3 class="font-bold mb-2">Results:</h3>
<div class="bg-gray-50 rounded p-3 max-h-96 overflow-auto">
<pre id="resultsText" class="text-sm whitespace-pre-wrap"></pre>
</div>
</div>
</div>
</div>
<script>
async function searchDocs() {
const query = document.getElementById('searchQuery').value.trim();
const scope = document.getElementById('searchScope').value;
if (!query) {
alert('Please enter a search query');
return;
}
try {
const result = await pt.searchDocuments(query, scope);
document.getElementById('resultsText').textContent = result.results;
document.getElementById('results').classList.remove('hidden');
} catch (error) {
alert('Search failed: ' + error.message);
}
}
</script>
View Document Text
Retrieve and display text from a document:
<div class="container mx-auto p-6 max-w-2xl">
<h1 class="text-2xl font-bold mb-4">View Document</h1>
<div class="bg-white rounded-lg shadow p-6">
<input
type="number"
id="docId"
placeholder="Document ID"
class="border rounded px-3 py-2 w-full mb-3"
>
<button
onclick="viewDoc()"
class="bg-purple-500 text-white px-4 py-2 rounded w-full hover:bg-purple-600"
>
View Text
</button>
<div id="docContent" class="mt-4 hidden">
<h3 class="font-bold mb-2">Document Content:</h3>
<div class="bg-gray-50 rounded p-3 max-h-96 overflow-auto">
<pre id="docText" class="text-sm whitespace-pre-wrap"></pre>
</div>
</div>
</div>
</div>
<script>
async function viewDoc() {
const docId = parseInt(document.getElementById('docId').value);
if (!docId) {
alert('Please enter a document ID');
return;
}
try {
const result = await pt.getDocumentText(docId);
if (result.text) {
document.getElementById('docText').textContent = result.text;
document.getElementById('docContent').classList.remove('hidden');
} else {
alert(result.message || 'No text available');
}
} catch (error) {
alert('Error: ' + error.message);
}
}
</script>
Create and Save Documents
Create documents in various formats:
<div class="container mx-auto p-6 max-w-2xl">
<h1 class="text-2xl font-bold mb-4">Create Document</h1>
<div class="bg-white rounded-lg shadow p-6">
<input
type="text"
id="filename"
placeholder="Filename (e.g., report.txt)"
class="border rounded px-3 py-2 w-full mb-3"
>
<select id="format" class="border rounded px-3 py-2 w-full mb-3">
<option value="TXT">Plain Text (.txt)</option>
<option value="MD">Markdown (.md)</option>
<option value="HTML">HTML (.html)</option>
<option value="PDF">PDF (use Markdown)</option>
<option value="DOCX">Word (use Markdown)</option>
<option value="CSV">CSV (.csv)</option>
</select>
<textarea
id="content"
rows="8"
placeholder="Enter content..."
class="border rounded px-3 py-2 w-full mb-3 font-mono text-sm"
></textarea>
<button
onclick="saveDoc()"
class="bg-indigo-500 text-white px-4 py-2 rounded w-full hover:bg-indigo-600"
>
Save Document
</button>
</div>
</div>
<script>
const mimeTypes = {
'TXT': 'text/plain',
'MD': 'text/markdown',
'HTML': 'text/html',
'PDF': 'application/pdf',
'DOCX': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'CSV': 'text/csv'
};
async function saveDoc() {
const filename = document.getElementById('filename').value.trim();
const format = document.getElementById('format').value;
const content = document.getElementById('content').value;
if (!filename || !content) {
alert('Please provide filename and content');
return;
}
try {
await pt.saveDocument(filename, format, mimeTypes[format], content);
alert('Document saved successfully!');
document.getElementById('filename').value = '';
document.getElementById('content').value = '';
} catch (error) {
alert('Error: ' + error.message);
}
}
</script>
Combine file uploads with AI instructions to automatically extract and store data:
<div class="container mx-auto p-6 max-w-2xl">
<h1 class="text-2xl font-bold mb-4">AI Data Extractor</h1>
<div class="bg-white rounded-lg shadow p-6">
<select id="taskType" class="border rounded px-3 py-2 w-full mb-3">
<option value="invoice">Extract Invoice Data</option>
<option value="resume">Parse Resume</option>
<option value="receipt">Process Expense Receipt</option>
</select>
<input
type="file"
id="fileUpload"
multiple
class="block w-full mb-3"
>
<button
onclick="processWithAI()"
class="bg-purple-500 text-white px-4 py-2 rounded w-full hover:bg-purple-600"
>
Process with AI
</button>
</div>
</div>
<script>
const instructions = {
invoice: `Extract invoice information and use the tool 'chatdb_add' to create database records:
- entity_name: "invoice"
- data: { invoice_number, date, vendor, amount, due_date }`,
resume: `Extract candidate information and use the tool 'chatdb_add' to create entries:
- entity_name: "candidate"
- data: { name, email, phone, skills: array, experience: number }`,
receipt: `Extract expense data and use the tool 'chatdb_add' to store each:
- entity_name: "expense"
- data: { date, merchant, amount, category }`
};
async function processWithAI() {
const task = document.getElementById('taskType').value;
const input = document.getElementById('fileUpload');
if (input.files.length === 0) {
alert('Please select files');
return;
}
const formData = new FormData();
for (const file of input.files) {
formData.append('files', file);
}
try {
await pt.uploadFiles(formData, instructions[task]);
alert('Files uploaded! AI is processing and storing data...');
input.value = '';
} catch (error) {
alert('Error: ' + error.message);
}
}
</script>
Direct AI Commands
Send natural language commands to have AI manage the database:
<div class="container mx-auto p-6 max-w-2xl">
<h1 class="text-2xl font-bold mb-4">AI Assistant</h1>
<div class="bg-white rounded-lg shadow p-6">
<!-- Quick Actions -->
<div class="grid grid-cols-2 gap-2 mb-4">
<button
onclick="aiCommand('competitors')"
class="bg-blue-100 text-blue-800 px-3 py-2 rounded hover:bg-blue-200"
>
Research Competitors
</button>
<button
onclick="aiCommand('analyze')"
class="bg-green-100 text-green-800 px-3 py-2 rounded hover:bg-green-200"
>
Analyze Tasks
</button>
</div>
<!-- Custom Command -->
<textarea
id="aiCommand"
rows="4"
placeholder="Enter AI command..."
class="border rounded px-3 py-2 w-full mb-3"
></textarea>
<button
onclick="sendCommand()"
class="bg-indigo-500 text-white px-4 py-2 rounded w-full hover:bg-indigo-600"
>
Execute
</button>
</div>
</div>
<script>
const commands = {
competitors: `Search for top 3 AI assistant competitors and use the tool 'chatdb_add' to store:
- entity_name: "competitor"
- data: { name, website, key_features: array }`,
analyze: `Use the tool 'chatdb_list' to find all pending tasks.
Use the tool 'chatdb_add' to create urgency report for each:
- entity_name: "urgent_task"
- data: { task_id, title, days_old, priority }`
};
async function aiCommand(type) {
try {
await pt.addMessage(commands[type]);
alert('AI is processing your request...');
} catch (error) {
alert('Error: ' + error.message);
}
}
async function sendCommand() {
const command = document.getElementById('aiCommand').value.trim();
if (!command) {
alert('Please enter a command');
return;
}
try {
await pt.addMessage(command);
alert('Command sent to AI assistant!');
document.getElementById('aiCommand').value = '';
} catch (error) {
alert('Error: ' + error.message);
}
}
</script>
Key Concepts Demonstrated
These examples cover:
Basic CRUD Operations: Create, read, update, and delete entities
Filtering: Using server-side filters to search data
State Management: Managing application state with entities
User Interface: Building interactive UIs with Tailwind CSS
Event Handling: Responding to user interactions
Data Display: Rendering lists and cards
Form Handling: Collecting and validating user input
Chat Integration: Sending messages to chat from Live Pages
File Upload: Uploading files with drag & drop support
Push Notifications: Send notifications to specific users
Document Search: Semantic search across documents and collections
Document Management: View and create documents in various formats
AI-Powered Automation: Let AI extract and store data automatically
Natural Language Commands: Control database with AI using plain language
Next Steps
Now that you've seen these basic examples, you can:
09 November 2025