@slorenzot/memento-web-ui
v0.2.5
Published
Next.js Web UI for Memento persistent memory system
Readme
@slorenzot/memento-web-ui
Modern React components and hooks for building Memento-powered web interfaces with Tailwind CSS styling and state management integration.
🚀 Installation
# Using Bun (recommended)
bun add @slorenzot/memento-web-ui
# Using npm
npm install @slorenzot/memento-web-ui
# Using yarn
yarn add @slorenzot/memento-web-ui💡 Basic Usage
TypeScript
import { App } from '@slorenzot/memento-web-ui';
import { useMemory } from '@slorenzot/memento-web-ui';
function MyComponent() {
const { observations, search, create } = useMemory();
return (
<div>
<button onClick={() => search('architecture')}>
Search
</button>
<App />
</div>
);
}Shell/Bun
# Run web application
bunx @slorenzot/memento-web-ui
# Or with custom port
PORT=5174 bunx @slorenzot/memento-web-ui🔧 Core API
Main Components
App
Main component of the Memento Web UI application.
Props:
{
dbPath?: string; // Custom database path
apiBase?: string; // Custom API base URL
theme?: 'light' | 'dark'; // Application theme
}Example:
import { App } from '@slorenzot/memento-web-ui';
function RootComponent() {
return (
<App
dbPath="./data/memento.db"
apiBase="http://localhost:3000/api"
theme="light"
/>
);
}Custom Hooks
useMemory()
Main hook for accessing memory functionality.
Returns:
{
observations: Observation[];
sessions: Session[];
search: (query: SearchParams) => Promise<SearchResult>;
createObservation: (data: CreateObservationData) => Promise<Observation>;
updateObservation: (id: number, data: UpdateObservationData) => Promise<Observation>;
deleteObservation: (id: number) => Promise<void>;
loading: boolean;
error: Error | null;
}Example:
function ObservationList() {
const { observations, search, loading } = useMemory();
const handleSearch = async () => {
const results = await search({
query: 'architecture',
type: 'decision'
});
console.log('Results:', results);
};
return (
<div>
<button onClick={handleSearch}>
{loading ? 'Searching...' : 'Search'}
</button>
<ul>
{observations.map(obs => (
<li key={obs.id}>{obs.title}</li>
))}
</ul>
</div>
);
}useSession()
Hook for managing active sessions.
Returns:
{
activeSession: Session | null;
startSession: (data: CreateSessionData) => Promise<Session>;
endSession: (id: number) => Promise<Session>;
loading: boolean;
}Example:
function SessionManager() {
const { activeSession, startSession, endSession, loading } = useSession();
const handleStart = async () => {
const session = await startSession({
projectId: 'my-app',
metadata: { agent: 'web-ui' }
});
console.log('Session started:', session.uuid);
};
const handleEnd = async () => {
if (activeSession) {
await endSession(activeSession.id);
}
};
return (
<div>
{!activeSession ? (
<button onClick={handleStart}>
{loading ? 'Starting...' : 'Start Session'}
</button>
) : (
<button onClick={handleEnd}>
{loading ? 'Ending...' : 'End Session'}
</button>
)}
</div>
);
}useSearch()
Specialized hook for search functionality.
Parameters:
debounceMs(number): Debounce time in ms (default: 300)
Returns:
{
query: string;
results: SearchResult | null;
searching: boolean;
setQuery: (query: string) => void;
search: (params: SearchParams) => Promise<SearchResult>;
}Example:
function SearchComponent() {
const { query, setQuery, results, searching } = useSearch({ debounceMs: 300 });
return (
<div>
<input
type="text"
value={query}
onChange={(e) => setQuery(e.target.value)}
placeholder="Search memory..."
/>
{searching && <p>Searching...</p>}
{results && (
<ul>
{results.observations.map(obs => (
<li key={obs.id}>
<strong>{obs.title}</strong>
<p>{obs.content.substring(0, 100)}...</p>
</li>
))}
</ul>
)}
</div>
);
}🎨 UI Components
ObservationCard
Card component for displaying an individual observation.
Props:
{
observation: Observation;
onEdit?: (id: number) => void;
onDelete?: (id: number) => void;
compact?: boolean;
}Example:
function ObservationsList() {
const { observations } = useMemory();
return (
<div className="grid gap-4">
{observations.map(obs => (
<ObservationCard
key={obs.id}
observation={obs}
compact={true}
onEdit={(id) => console.log('Edit:', id)}
onDelete={(id) => console.log('Delete:', id)}
/>
))}
</div>
);
}SearchBox
Search component with autocomplete.
Props:
{
placeholder?: string;
onSearch: (query: string) => void;
filters?: SearchFilters;
debounce?: number;
}Example:
function Header() {
const handleSearch = (query: string) => {
console.log('Searching:', query);
};
return (
<header className="bg-white shadow">
<SearchBox
placeholder="Search observations, decisions, bugs..."
onSearch={handleSearch}
filters={{
types: ['decision', 'bug', 'discovery', 'note'],
defaultType: 'all'
}}
debounce={300}
/>
</header>
);
}StatsPanel
Memory system statistics panel.
Props:
{
projectId?: string;
refreshInterval?: number; // ms for auto-refresh
}Example:
function Dashboard() {
return (
<div className="p-6">
<StatsPanel
projectId="my-app"
refreshInterval={60000} // Refresh every minute
/>
</div>
);
}TimelineView
Observation timeline view.
Props:
{
observations: Observation[];
groupBy?: 'day' | 'week' | 'month';
onObservationClick?: (id: number) => void;
}Example:
function Timeline() {
const { observations } = useMemory();
return (
<div className="max-w-4xl mx-auto">
<TimelineView
observations={observations}
groupBy="day"
onObservationClick={(id) => console.log('Click:', id)}
/>
</div>
);
}⚡ Practical Examples
Example 1: Full Next.js Integration
// app/page.tsx
'use client';
import { App, useMemory } from '@slorenzot/memento-web-ui';
export default function Home() {
const { observations, loading } = useMemory();
return (
<main className="min-h-screen bg-gray-100">
<div className="container mx-auto p-6">
<h1 className="text-3xl font-bold mb-6">
Memento Memory System
</h1>
{loading ? (
<p className="text-center">Loading observations...</p>
) : (
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-3">
{observations.map(obs => (
<ObservationCard
key={obs.id}
observation={obs}
/>
))}
</div>
)}
</div>
</main>
);
}Example 2: Advanced Search Component
import { useSearch, SearchBox } from '@slorenzot/memento-web-ui';
function AdvancedSearch() {
const { query, setQuery, results, searching } = useSearch();
const filters = {
types: ['decision', 'bug', 'discovery', 'note'],
defaultType: 'decision'
};
return (
<div className="max-w-2xl mx-auto p-6">
<h2 className="text-2xl font-bold mb-4">
Advanced Search
</h2>
<SearchBox
value={query}
onChange={setQuery}
placeholder="Search memory..."
filters={filters}
/>
{searching && (
<div className="mt-4 text-center">
<div className="inline-block animate-spin rounded-full h-8 w-8 border-b-2 border-gray-900"></div>
<p className="ml-2">Searching...</p>
</div>
)}
{results && results.observations.length > 0 && (
<div className="mt-6">
<h3 className="text-xl font-semibold mb-3">
Results ({results.total})
</h3>
<div className="space-y-4">
{results.observations.map(obs => (
<ObservationCard
key={obs.id}
observation={obs}
/>
))}
</div>
</div>
)}
</div>
);
}Example 3: Admin Panel
import { useMemory, useSession, StatsPanel } from '@slorenzot/memento-web-ui';
function AdminPanel() {
const { loading, error } = useMemory();
const { activeSession, startSession, endSession } = useSession();
return (
<div className="max-w-6xl mx-auto p-6">
<div className="grid gap-6 lg:grid-cols-2">
{/* Session Panel */}
<div className="bg-white rounded-lg shadow p-6">
<h2 className="text-xl font-bold mb-4">
Session Management
</h2>
{activeSession ? (
<div className="space-y-3">
<p className="text-green-600 font-medium">
✓ Active session: {activeSession.uuid}
</p>
<button
onClick={() => endSession(activeSession.id)}
className="w-full bg-red-500 text-white px-4 py-2 rounded hover:bg-red-600"
>
End Session
</button>
</div>
) : (
<button
onClick={() => startSession({ projectId: 'admin' })}
className="w-full bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600"
>
Start New Session
</button>
)}
</div>
{/* Statistics Panel */}
<div className="bg-white rounded-lg shadow p-6">
<h2 className="text-xl font-bold mb-4">
System Statistics
</h2>
<StatsPanel refreshInterval={30000} />
</div>
</div>
{/* Status Messages */}
{loading && (
<div className="mt-6 bg-blue-50 text-blue-700 p-4 rounded">
Loading system data...
</div>
)}
{error && (
<div className="mt-6 bg-red-50 text-red-700 p-4 rounded">
Error: {error.message}
</div>
)}
</div>
);
}Example 4: Standalone Application
// index.tsx
import { App } from '@slorenzot/memento-web-ui';
// Custom configuration
const config = {
dbPath: process.env.MEMENTO_DB_PATH || './data/memento.db',
apiBase: process.env.MEMENTO_API_URL || 'http://localhost:3000/api',
theme: (localStorage.getItem('theme') as 'light' | 'dark') || 'light'
};
// Render application
document.getElementById('root').render(
<App {...config} />
);🔧 Configuration
App Component Props
interface AppProps {
dbPath?: string; // Database path (default: './data/memento.db')
apiBase?: string; // API base URL (default: 'http://localhost:3000/api')
theme?: 'light' | 'dark'; // App theme (default: 'light')
locale?: string; // UI language (default: 'es')
}Environment Variables
MEMENTO_DB_PATH: Custom database pathMEMENTO_API_URL: Custom API base URLMEMENTO_THEME: Default theme ('light'|'dark')MEMENTO_LOCALE: Default language
Example:
# Configure environment
export MEMENTO_API_URL="http://api.example.com/api"
export MEMENTO_THEME="dark"
# Run application
bunx @slorenzot/memento-web-ui⚠️ Restrictive License
This package is under CC BY-NC-ND 4.0 License:
- ✅ Personal and educational use permitted
- ✅ Share with attribution to the author
- ❌ Commercial use NOT permitted
- ❌ Modifications or forks NOT permitted
Author: Soulberto Lorenzo ([email protected])
🔄 Dependencies
Main Dependencies
react- UI frameworkreact-dom- Browser rendering@tanstack/react-query- State and cache managementzustand- Global state managementclsx- CSS class utilitydate-fns- Date formattinglucide-react- SVG iconszod- Schema validation
Peer Dependencies
reactv18+react-domv18+
🛠️ Development
# Clone the project
git clone https://github.com/slorenzot/memento.git
cd memento/packages/web-ui
# Install dependencies
bun install
# Development
bun run dev
# Build
bun run build
# Preview build
bun run preview📋 Changelog
[0.1.0] - 2024-04-04
- Added: Initial version of React components
- Added: Custom hooks (useMemory, useSession, useSearch)
- Added: UI components (ObservationCard, SearchBox, StatsPanel)
- Added: Tailwind CSS integration
- Added: Light/dark theme support
👤 Author
Soulberto Lorenzo
- GitHub: @slorenzot
- Email: [email protected]
📄 License
This package is licensed under Creative Commons Attribution-NonCommercial-NoDerivs 4.0 International.
⚠️ Important: This package has a restrictive license. Please respect the CC BY-NC-ND 4.0 license terms.
