@parent-tobias/filesystem-component
v0.1.0
Published
A flexible, feature-rich filesystem web component with version control, multiple storage backends (IndexedDB, OPFS, File System Access API), and comprehensive theming support
Downloads
125
Maintainers
Readme
Filesystem Component
A flexible, feature-rich filesystem web component built with Lit.js and TypeScript. This component provides a complete file management system with version control, multiple storage backends, and a clean UI.
Features
- Full Filesystem Operations: Create, read, update, delete files and folders
- Version Control: Auto-save and named versions with history tracking
- Multiple Storage Backends:
- File System Access API - Save to real, visible files in user-chosen directories ✨ NEW
- OPFS (Origin Private File System) - Modern browser API
- IndexedDB - Fallback for broader compatibility
- Automatic fallback from OPFS to IndexedDB
- Extensible for remote storage (API, Supabase, Firebase, etc.)
- File References: Files can exist in multiple folders (like tags/labels)
- Folder Hierarchy: Nested folders with breadcrumb navigation
- Fork/Clone Files: Create copies from any version
- Custom Events: React to user interactions (file selection, saves, etc.)
- Public API: Programmatic control via methods
- Auto-save: Debounced auto-saving with configurable timing
- Clean UI: Polished sidebar interface with Material Design inspired styling
- Comprehensive Theming: Full CSS custom properties support for colors, spacing, typography, and more
Installation
npm install
npm run devUsage
Basic Setup
<!DOCTYPE html>
<html>
<head>
<script type="module" src="/src/index.ts"></script>
</head>
<body>
<filesystem-component></filesystem-component>
</body>
</html>With TypeScript
import { FileSystemComponent } from './filesystem-component';
const fileSystem = document.querySelector('filesystem-component') as FileSystemComponent;
// Create a file
const fileId = await fileSystem.createFile('hello.txt', 'Hello, World!');
// Load a file
const result = await fileSystem.loadFile(fileId);
console.log(result?.content); // "Hello, World!"
// Save a file (auto-save)
await fileSystem.saveFile(fileId, 'Updated content', { autoSave: true });
// Save a named version
await fileSystem.saveFile(fileId, 'Version 1.0 content', {
autoSave: false,
versionName: 'v1.0'
});Custom Events
// Listen for file selection
fileSystem.addEventListener('file-selected', (e: Event) => {
const detail = (e as CustomEvent).detail;
console.log('Selected file:', detail.fileName);
console.log('Breadcrumb:', detail.breadcrumb);
});
// Listen for folder selection
fileSystem.addEventListener('folder-selected', (e: Event) => {
const detail = (e as CustomEvent).detail;
console.log('Selected folder:', detail.folderName);
console.log('Path:', detail.folderPath);
});
// Other events
fileSystem.addEventListener('file-created', (e) => { /* ... */ });
fileSystem.addEventListener('file-saved', (e) => { /* ... */ });
fileSystem.addEventListener('file-forked', (e) => { /* ... */ });
fileSystem.addEventListener('version-restored', (e) => { /* ... */ });Theming
The component supports comprehensive theming through CSS custom properties. You can customize colors, spacing, typography, and more to match your application's design system.
Quick Example
/* Override default theme */
filesystem-component {
--fs-color-primary: #8b5cf6;
--fs-color-bg-primary: #1a1a1a;
--fs-color-text-primary: #ffffff;
--fs-spacing-sm: 6px;
--fs-font-family: 'Inter', sans-serif;
}Integrate with Other Components
/* Define global theme variables */
:root {
--app-color-primary: #0066cc;
--app-color-bg: white;
--app-spacing: 8px;
}
/* Apply to filesystem component */
filesystem-component {
--fs-color-primary: var(--app-color-primary);
--fs-color-bg-primary: var(--app-color-bg);
--fs-spacing-sm: var(--app-spacing);
}
/* Apply to other components */
chordpro-editor,
chordpro-renderer {
--chord-color-primary: var(--app-color-primary);
--chord-color-bg: var(--app-color-bg);
}Available CSS Custom Properties
The component exposes 40+ CSS custom properties covering:
- Colors: Base backgrounds, text colors, borders, brand/action colors
- Spacing: From extra small (4px) to extra large (32px)
- Typography: Font family, sizes (11px-16px), weights
- Effects: Shadows, transitions, border radius
- Dimensions: Content max height
For complete documentation of all CSS custom properties, see THEMING.md.
For a live demo, open examples/theming-demo.html in your browser.
API Reference
File Operations
createFile(name: string, content: string, folderId?: string): Promise<string>
Creates a new file with optional folder placement.
const fileId = await fileSystem.createFile('document.txt', 'Initial content', folderId);loadFile(fileId: string, versionId?: string): Promise<{file: FileMetadata, content: string} | null>
Loads a file's content. Optionally specify a version to load.
const result = await fileSystem.loadFile(fileId);
const oldVersion = await fileSystem.loadFile(fileId, versionId);saveFile(fileId: string, content: string, options: SaveFileOptions): Promise<string>
Saves a file, creating a new version.
// Auto-save
await fileSystem.saveFile(fileId, content, { autoSave: true });
// Named version
await fileSystem.saveFile(fileId, content, {
autoSave: false,
versionName: 'Release v1.0'
});deleteFile(fileId: string): Promise<void>
Deletes a file and all its versions.
renameFile(fileId: string, newName: string): Promise<void>
Renames a file.
forkFile(fileId: string, versionId?: string, newName?: string): Promise<string>
Creates a copy of a file from a specific version.
const newFileId = await fileSystem.forkFile(fileId, versionId, 'Forked Document');Folder Operations
createFolder(name: string, parentId?: string): Promise<string>
Creates a new folder.
const folderId = await fileSystem.createFolder('My Projects');
const subfolderId = await fileSystem.createFolder('Client Work', folderId);deleteFolder(folderId: string): Promise<void>
Deletes a folder (files are unlinked, not deleted).
renameFolder(folderId: string, newName: string): Promise<void>
Renames a folder.
moveFileToFolder(fileId: string, folderId: string): Promise<void>
Links a file to a folder (file can exist in multiple folders).
Version Control
getVersionHistory(fileId: string): Promise<VersionInfo[]>
Gets all versions of a file.
const history = await fileSystem.getVersionHistory(fileId);
history.forEach(v => {
console.log(v.name, v.timestamp, v.isAuto);
});restoreVersion(fileId: string, versionId: string): Promise<string>
Restores an old version (creates a new version with old content).
await fileSystem.restoreVersion(fileId, oldVersionId);pruneVersions(fileId: string, options: PruneOptions): Promise<void>
Removes old auto-save versions.
await fileSystem.pruneVersions(fileId, {
keepLast: 10,
keepNamed: true
});Query Operations
getAllFiles(): Promise<FileMetadata[]>
Gets all files in the system.
getAllFolders(): Promise<FolderMetadata[]>
Gets all folders in the system.
refresh(): Promise<void>
Refreshes the UI from storage.
Storage Architecture
Storage Options
The component supports three storage backends:
- OPFS (Origin Private File System) - Modern, sandboxed browser storage
- IndexedDB - Fallback for broader compatibility
- File System Access API - Save to user-chosen folders as real files ✨ NEW
Automatic Fallback
By default, the component tries OPFS first, then falls back to IndexedDB if OPFS is unavailable.
Storage Types
// Default: auto-fallback (OPFS → IndexedDB)
<filesystem-component></filesystem-component>
// Force IndexedDB
<filesystem-component storage-type="indexeddb"></filesystem-component>
// Force OPFS
<filesystem-component storage-type="opfs"></filesystem-component>
// Force File System Access (user picks directory)
<filesystem-component storage-type="filesystemaccess"></filesystem-component>File System Access API
What makes it special:
- ✅ Files saved as real, visible files in your chosen directory
- ✅ Access files outside the browser (using any text editor)
- ✅ Folder structure matches real directories
- ✅ Choose where to save your data
- ⚠️ Requires user permission (browser will prompt)
- ⚠️ Chrome/Edge 86+, not available in Firefox/Safari yet
How to use:
- Click the "📁 Pick Folder" button in the component header
- Choose a directory on your computer
- Grant read/write permission
- Files are now saved as real files!
✨ Persistence:
- Your directory selection is automatically saved to IndexedDB
- On page reload, the directory auto-restores if permission is still granted
- No need to pick the folder again after refreshing!
- See PERSISTENCE.md for details
What gets created:
your-chosen-folder/
├── .fs-meta/ # Hidden metadata directory
│ ├── files.json # File metadata
│ ├── folders.json # Folder structure
│ └── versions/ # Version history
│ ├── v1.json
│ └── v2.json
├── My Documents/ # Your actual folders
│ ├── report.txt # Your actual files!
│ └── notes.txt
└── Projects/
└── todo.mdProgrammatic usage:
const fileSystem = document.querySelector('filesystem-component');
// Switch to File System Access storage
await fileSystem.service.switchToFileSystemAccess();
// This prompts user to pick a directory
// Now all operations save to real files
await fileSystem.createFile('document.txt', 'Hello!');Custom Storage Adapter
Implement the StorageAdapter interface for custom backends:
import { StorageAdapter } from './storage/storage-adapter';
class RemoteStorageAdapter implements StorageAdapter {
async getFile(id: string) { /* API call */ }
async saveFile(file: FileMetadata) { /* API call */ }
// ... implement all methods
}Version Control Strategy
Auto-Save Versions
- Created automatically after 2 seconds of inactivity
- Timestamped:
v_20231213_143022 - Old versions auto-pruned (keeps last 10)
Named Versions
- Created manually by user
- Custom names: "v1.0", "First Draft", etc.
- Never auto-pruned
- Permanent record of important states
File Forking
Clone any version into a new file for experimentation.
Events Reference
| Event | Detail | Description |
|-------|--------|-------------|
| file-selected | FileSelectedDetail | User clicked a file |
| folder-selected | FolderSelectedDetail | User clicked a folder |
| file-created | { fileName: string } | New file created |
| file-saved | { fileId, versionId, isAutoSave } | File saved |
| file-deleted | { fileId } | File deleted |
| file-forked | { originalFileId, newFileId } | File forked |
| folder-created | { folderName } | Folder created |
| folder-deleted | { folderId } | Folder deleted |
| version-restored | { fileId, versionId, newVersionId } | Version restored |
Development
# Install dependencies
npm install
# Run dev server
npm run dev
# Build
npm run build
# Preview build
npm run previewBrowser Support
- File System Access API: Chrome 86+, Edge 86+ (real files in user directories)
- OPFS: Chrome 86+, Edge 86+, Opera 72+ (sandboxed browser storage)
- IndexedDB: All modern browsers (fallback)
License
MIT
Future Enhancements
- Remote storage adapters (Supabase, Firebase, custom API)
- Search functionality
- File tagging
- Drag-and-drop file organization
- Export/import functionality
- Collaborative editing support
- Conflict resolution for concurrent edits
