diff --git a/lite/.gitignore b/lite/.gitignore new file mode 100644 index 00000000..7af92926 --- /dev/null +++ b/lite/.gitignore @@ -0,0 +1,5 @@ +node_modules +dist +out +*.vsix +.vscode-test/ diff --git a/lite/.vscodeignore b/lite/.vscodeignore new file mode 100644 index 00000000..ae886703 --- /dev/null +++ b/lite/.vscodeignore @@ -0,0 +1,9 @@ +.vscode/** +.vscode-test/** +src/** +.gitignore +tsconfig.json +webpack.config.js +node_modules/** +*.map +*.ts diff --git a/lite/DEVELOPMENT.md b/lite/DEVELOPMENT.md new file mode 100644 index 00000000..25eec6ed --- /dev/null +++ b/lite/DEVELOPMENT.md @@ -0,0 +1,113 @@ +# Development Guide - Front Matter Lite + +## Prerequisites + +- Node.js (v18 or higher) +- npm or yarn + +## Setup + +```bash +cd lite +npm install +``` + +## Building + +### Development Build + +```bash +npm run dev +``` + +This will watch for changes and rebuild automatically. + +### Production Build + +```bash +npm run build +``` + +## Testing + +### Local Testing + +1. Build the extension: + ```bash + npm run build + ``` + +2. Press F5 in VS Code to open the Extension Development Host + +3. Test in a virtual workspace: + - Open the Command Palette (F1) + - Run "Open Remote Repository" + - Enter a GitHub repository URL + - Test the lite version features + +### Testing in github.dev + +1. Package the extension: + ```bash + npm install -g @vscode/vsce + vsce package + ``` + +2. Navigate to github.dev in your browser + - Press `.` on any GitHub repository + - Install the extension manually + +## Architecture + +The lite version is designed to work without Node.js-specific APIs: + +- **No Node.js fs module** - Uses `vscode.workspace.fs` instead +- **No Node.js path module** - Uses `vscode.Uri.joinPath` instead +- **No child_process** - No external script execution +- **Browser-compatible** - Built as a web extension (target: 'webworker') + +## Key Differences from Full Extension + +| Feature | Full Extension | Lite Version | +|---------|---------------|--------------| +| File Operations | Node.js `fs` | VS Code `workspace.fs` | +| Path Handling | Node.js `path` | `vscode.Uri` | +| Scripts | child_process | Not available | +| Workspace | File system only | Virtual workspaces | +| Dashboard | Full React app | Simplified (planned) | + +## Contributing + +When adding features to the lite version: + +1. Ensure compatibility with virtual workspaces +2. Use only browser-compatible APIs +3. Test in both github.dev and vscode.dev +4. Document any limitations + +## Debugging + +Enable the Output Channel "Front Matter Lite" to see debug messages: + +1. View > Output +2. Select "Front Matter Lite" from the dropdown + +## Common Issues + +### Extension not loading + +- Check the Output channel for errors +- Ensure the extension is built correctly +- Verify the package.json has the correct `browser` entry point + +### Features not working in virtual workspace + +- Confirm the workspace scheme is not 'file' +- Check browser console for errors +- Verify you're using VS Code FileSystem API + +## Resources + +- [VS Code Web Extensions Guide](https://code.visualstudio.com/api/extension-guides/web-extensions) +- [Virtual Workspaces Documentation](https://code.visualstudio.com/api/extension-guides/virtual-workspaces) +- [Front Matter Documentation](https://frontmatter.codes) diff --git a/lite/README.md b/lite/README.md new file mode 100644 index 00000000..9b377401 --- /dev/null +++ b/lite/README.md @@ -0,0 +1,95 @@ +# Front Matter CMS (Lite) + +This is the lite version of Front Matter CMS designed specifically for **virtual workspaces** such as github.dev and vscode.dev. + +## What is a Virtual Workspace? + +Virtual workspaces allow you to work with code directly in your browser without cloning a repository locally. This includes: + +- **github.dev** - Press `.` on any GitHub repository +- **vscode.dev** - Open VS Code in your browser +- **GitHub Codespaces** - Cloud-based development environments + +## Features + +The lite version provides core content management functionality: + +### ✅ Supported Features + +- **Register Content Folders** - Right-click on folders in the Explorer to register them as content folders +- **Create Content** - Create new markdown files with front matter +- **View Configuration** - Manage your content folder settings + +### ❌ Limited/Unavailable Features + +The following features from the full extension are not available in the lite version due to virtual workspace limitations: + +- **Dashboard** - Full dashboard UI (under development) +- **Media Management** - File upload and media library +- **Local Server Preview** - Starting/stopping local dev servers +- **Git Integration** - Advanced git operations +- **Custom Scripts** - Running custom Node.js scripts +- **File System Watch** - Automatic content refresh +- **Complex Build Tools** - Framework-specific integrations + +## Installation + +1. Open a virtual workspace (github.dev or vscode.dev) +2. Install the "Front Matter CMS (Lite)" extension from the Extensions marketplace +3. Start managing your content! + +## Usage + +### Register a Content Folder + +1. In the Explorer, right-click on any folder +2. Select **Front Matter Lite > Register Content Folder (Lite)** +3. Enter a title for the folder +4. The folder is now registered and can be used for content creation + +### Create New Content + +1. Open the Command Palette (F1 or Ctrl/Cmd+Shift+P) +2. Run **Front Matter Lite: Create Content (Lite)** +3. Select a content folder +4. Enter a file name +5. Your new content file is created with basic front matter + +## Configuration + +The lite version uses the same configuration as the full extension. You can configure your content folders and content types in VS Code settings: + +```json +{ + "frontMatter.content.pageFolders": [ + { + "title": "Blog Posts", + "path": "content/blog" + } + ] +} +``` + +## Limitations + +This lite version is designed to work within the constraints of virtual workspaces: + +- Uses only the VS Code FileSystem API +- No Node.js file system operations +- No external process execution +- Limited to browser-compatible APIs + +## Need More Features? + +For the full Front Matter CMS experience with all features, install the regular extension in VS Code Desktop: + +- [Front Matter CMS on the VS Code Marketplace](https://marketplace.visualstudio.com/items?itemName=eliostruyf.vscode-front-matter) +- [Documentation](https://frontmatter.codes) + +## Contributing + +This is part of the Front Matter CMS project. Visit our [GitHub repository](https://github.com/estruyf/vscode-front-matter) to contribute or report issues. + +## License + +MIT diff --git a/lite/package.json b/lite/package.json new file mode 100644 index 00000000..fd2a9111 --- /dev/null +++ b/lite/package.json @@ -0,0 +1,141 @@ +{ + "name": "vscode-front-matter-lite", + "displayName": "Front Matter CMS (Lite)", + "description": "Front Matter CMS lite version for virtual workspaces (github.dev, vscode.dev). Provides basic content management features with limited functionality compared to the full extension.", + "icon": "assets/frontmatter-teal-128x128.png", + "version": "10.9.0", + "preview": true, + "publisher": "eliostruyf", + "galleryBanner": { + "color": "#0e131f", + "theme": "dark" + }, + "engines": { + "vscode": "^1.90.0" + }, + "categories": [ + "Other" + ], + "keywords": [ + "Front Matter", + "CMS", + "Markdown", + "Web Extension", + "Virtual Workspace" + ], + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/estruyf/vscode-front-matter" + }, + "capabilities": { + "virtualWorkspaces": true, + "untrustedWorkspaces": { + "supported": true + } + }, + "browser": "./dist/extension-web.js", + "activationEvents": [ + "workspaceContains:**/.frontmatter", + "workspaceContains:**/frontmatter.json" + ], + "contributes": { + "commands": [ + { + "command": "frontMatter.lite.dashboard", + "title": "Open Dashboard (Lite)", + "category": "Front Matter Lite" + }, + { + "command": "frontMatter.lite.registerFolder", + "title": "Register Content Folder (Lite)", + "category": "Front Matter Lite" + }, + { + "command": "frontMatter.lite.createContent", + "title": "Create Content (Lite)", + "category": "Front Matter Lite" + } + ], + "configuration": { + "title": "Front Matter Lite", + "type": "object", + "properties": { + "frontMatter.content.pageFolders": { + "type": "array", + "default": [], + "markdownDescription": "Configure the folders that contain your content", + "items": { + "type": "object", + "properties": { + "title": { + "type": "string", + "description": "The title of the folder" + }, + "path": { + "type": "string", + "description": "The path to the folder" + } + }, + "required": [ + "title", + "path" + ] + } + }, + "frontMatter.taxonomy.contentTypes": { + "type": "array", + "default": [ + { + "name": "default", + "fields": [ + { + "title": "Title", + "name": "title", + "type": "string" + }, + { + "title": "Description", + "name": "description", + "type": "string" + }, + { + "title": "Publishing date", + "name": "date", + "type": "datetime" + }, + { + "title": "Tags", + "name": "tags", + "type": "tags" + } + ] + } + ], + "markdownDescription": "Configure your content types" + } + } + }, + "menus": { + "explorer/context": [ + { + "command": "frontMatter.lite.registerFolder", + "when": "explorerResourceIsFolder", + "group": "frontmatter@1" + } + ] + } + }, + "scripts": { + "vscode:prepublish": "npm run build", + "build": "webpack --mode production --config ./webpack.config.js", + "dev": "webpack --mode development --watch --config ./webpack.config.js" + }, + "devDependencies": { + "@types/vscode": "^1.90.0", + "ts-loader": "^9.4.2", + "typescript": "^4.9.5", + "webpack": "^5.75.0", + "webpack-cli": "^4.10.0" + } +} diff --git a/lite/src/extension.ts b/lite/src/extension.ts new file mode 100644 index 00000000..a26ae49b --- /dev/null +++ b/lite/src/extension.ts @@ -0,0 +1,213 @@ +import * as vscode from 'vscode'; + +/** + * Lite version of Front Matter CMS for virtual workspaces + * This version provides basic content management functionality using + * the VS Code FileSystem API which works in virtual workspaces like github.dev + */ + +let outputChannel: vscode.OutputChannel; + +export function activate(context: vscode.ExtensionContext) { + outputChannel = vscode.window.createOutputChannel('Front Matter Lite'); + outputChannel.appendLine('Front Matter Lite activated for virtual workspace'); + + // Register Dashboard command + context.subscriptions.push( + vscode.commands.registerCommand('frontMatter.lite.dashboard', async () => { + vscode.window.showInformationMessage( + 'Front Matter Lite Dashboard: This feature is under development for virtual workspaces' + ); + }) + ); + + // Register folder registration command + context.subscriptions.push( + vscode.commands.registerCommand('frontMatter.lite.registerFolder', async (uri: vscode.Uri) => { + try { + const config = vscode.workspace.getConfiguration('frontMatter'); + const pageFolders = config.get>('content.pageFolders') || []; + + // Get workspace folder + const workspaceFolder = vscode.workspace.getWorkspaceFolder(uri); + if (!workspaceFolder) { + vscode.window.showErrorMessage('No workspace folder found'); + return; + } + + // Calculate relative path + const relativePath = vscode.workspace.asRelativePath(uri, false); + + // Check if folder is already registered + const exists = pageFolders.some(f => f.path === relativePath); + if (exists) { + vscode.window.showInformationMessage(`Folder "${relativePath}" is already registered`); + return; + } + + // Prompt for folder title + const title = await vscode.window.showInputBox({ + prompt: 'Enter a title for this content folder', + value: relativePath + }); + + if (!title) { + return; + } + + // Add folder to configuration + pageFolders.push({ + title, + path: relativePath + }); + + await config.update('content.pageFolders', pageFolders, vscode.ConfigurationTarget.Workspace); + + vscode.window.showInformationMessage( + `Content folder "${title}" registered successfully!`, + 'View Configuration' + ).then(selection => { + if (selection === 'View Configuration') { + vscode.commands.executeCommand('workbench.action.openSettings', 'frontMatter.content.pageFolders'); + } + }); + + outputChannel.appendLine(`Registered content folder: ${title} (${relativePath})`); + } catch (error) { + vscode.window.showErrorMessage(`Failed to register folder: ${error}`); + outputChannel.appendLine(`Error registering folder: ${error}`); + } + }) + ); + + // Register create content command + context.subscriptions.push( + vscode.commands.registerCommand('frontMatter.lite.createContent', async () => { + try { + const config = vscode.workspace.getConfiguration('frontMatter'); + const pageFolders = config.get>('content.pageFolders') || []; + + if (pageFolders.length === 0) { + const action = await vscode.window.showWarningMessage( + 'No content folders configured. Please register a content folder first.', + 'Register Folder' + ); + + if (action === 'Register Folder') { + vscode.window.showInformationMessage( + 'Please right-click on a folder in the Explorer and select "Front Matter Lite > Register Content Folder"' + ); + } + return; + } + + // Select a content folder + const selectedFolder = await vscode.window.showQuickPick( + pageFolders.map(f => ({ label: f.title, description: f.path, folder: f })), + { placeHolder: 'Select a content folder' } + ); + + if (!selectedFolder) { + return; + } + + // Prompt for file name + const fileName = await vscode.window.showInputBox({ + prompt: 'Enter the file name (without extension)', + validateInput: (value) => { + if (!value) { + return 'File name is required'; + } + if (!/^[a-zA-Z0-9-_]+$/.test(value)) { + return 'File name can only contain letters, numbers, hyphens, and underscores'; + } + return null; + } + }); + + if (!fileName) { + return; + } + + // Create the file + const workspaceFolders = vscode.workspace.workspaceFolders; + if (!workspaceFolders) { + vscode.window.showErrorMessage('No workspace folder found'); + return; + } + + const folderUri = vscode.Uri.joinPath( + workspaceFolders[0].uri, + selectedFolder.folder.path + ); + + const fileUri = vscode.Uri.joinPath(folderUri, `${fileName}.md`); + + // Check if file already exists + try { + await vscode.workspace.fs.stat(fileUri); + vscode.window.showErrorMessage(`File "${fileName}.md" already exists`); + return; + } catch { + // File doesn't exist, continue + } + + // Create basic front matter content + const date = new Date().toISOString(); + const content = `--- +title: ${fileName} +description: +date: ${date} +tags: [] +--- + +# ${fileName} + +Your content here... +`; + + const encoder = new TextEncoder(); + await vscode.workspace.fs.writeFile(fileUri, encoder.encode(content)); + + // Open the file + const doc = await vscode.workspace.openTextDocument(fileUri); + await vscode.window.showTextDocument(doc); + + vscode.window.showInformationMessage(`Content "${fileName}.md" created successfully!`); + outputChannel.appendLine(`Created content: ${fileUri.fsPath}`); + } catch (error) { + vscode.window.showErrorMessage(`Failed to create content: ${error}`); + outputChannel.appendLine(`Error creating content: ${error}`); + } + }) + ); + + // Check if running in virtual workspace + if (vscode.workspace.workspaceFolders) { + const isVirtual = vscode.workspace.workspaceFolders.some( + folder => folder.uri.scheme !== 'file' + ); + + if (isVirtual) { + outputChannel.appendLine('Running in virtual workspace mode'); + vscode.window.showInformationMessage( + 'Front Matter Lite is running in virtual workspace mode. Some features may be limited.', + 'Learn More' + ).then(selection => { + if (selection === 'Learn More') { + vscode.env.openExternal( + vscode.Uri.parse('https://frontmatter.codes/docs/virtual-workspaces') + ); + } + }); + } + } + + outputChannel.appendLine('Front Matter Lite: All commands registered'); +} + +export function deactivate() { + if (outputChannel) { + outputChannel.dispose(); + } +} diff --git a/lite/tsconfig.json b/lite/tsconfig.json new file mode 100644 index 00000000..abc862db --- /dev/null +++ b/lite/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "module": "commonjs", + "target": "ES2020", + "outDir": "out", + "lib": ["ES2020"], + "sourceMap": true, + "rootDir": "src", + "strict": true, + "strictNullChecks": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true + }, + "exclude": ["node_modules", ".vscode-test"] +} diff --git a/lite/webpack.config.js b/lite/webpack.config.js new file mode 100644 index 00000000..c91ae630 --- /dev/null +++ b/lite/webpack.config.js @@ -0,0 +1,53 @@ +//@ts-check + +'use strict'; + +const path = require('path'); + +/**@type {import('webpack').Configuration}*/ +const config = { + target: 'webworker', // Web extension target + entry: './src/extension.ts', + output: { + path: path.resolve(__dirname, 'dist'), + filename: 'extension-web.js', + libraryTarget: 'commonjs2', + devtoolModuleFilenameTemplate: '../[resource-path]' + }, + devtool: 'nosources-source-map', + externals: { + vscode: 'commonjs vscode' // The vscode-module is created on-the-fly and must be excluded + }, + resolve: { + extensions: ['.ts', '.js'], + fallback: { + // Webpack 5 no longer polyfills Node.js core modules automatically + path: false, + fs: false, + os: false, + crypto: false, + stream: false, + assert: false, + buffer: false, + util: false + } + }, + module: { + rules: [ + { + test: /\.ts$/, + exclude: /node_modules/, + use: [ + { + loader: 'ts-loader' + } + ] + } + ] + }, + performance: { + hints: false + } +}; + +module.exports = config;