A high-performance, VS Code-like workspace shell widget for Flutter applications.
- VS Code Layout: Familiar structure with Activity Bar, Sidebar, and Editor Area.
- Split Editor: Support for vertical split panes to view multiple tabs side-by-side.
- Tab Management: Robust tab system with close actions, dirty state indicators, and drag-and-drop support.
- Persistence: Automatic state restoration of open tabs and sidebar state via
HydratedBloc. - Web Ready: Optimized for web deployments with responsive design and persistence support.
- High Performance: Optimized for large widget trees with O(1) state lookups and granular rebuilds.
- Custom Icons: Support for dynamic widgets (images, SVGs, etc.) via the
iconWidgetproperty across sidebar and tabs, preserving icon tree-shaking for web applications. - Customizable: Fully configurable activity bar, sidebar views, and page registry.
- Theme Aware: Seamlessly integrates with your application's
ThemeData, supporting both light and dark modes.
Add off_ide to your pubspec.yaml:
dependencies:
off_ide: ^0.1.2The main entry point is the WorkspaceShell widget, which requires a WorkspaceConfig.
There are two primary ways to define this configuration: Hardcoded (for simple, static apps) and Dynamic (for robust, backend-driven apps like CRMs).
For simple applications where the sidebar structure never changes, you can define your WorkspaceConfig statically:
import 'package:flutter/material.dart';
import 'package:off_ide/off_ide.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: WorkspaceShell(
config: WorkspaceConfig(
// 1. Define Activity Bar Items
activityBarItems: [
const ActivityBarItem(
id: 'files',
icon: Icons.folder_outlined,
label: 'Explorer',
),
],
// 2. Define Sidebar Content
sidebarViews: {
'files': const SidebarView(
id: 'files',
title: 'EXPLORER',
groups: [
MenuGroup(
id: 'project',
label: 'My Project',
items: [
MenuItem(
id: 'readme',
label: 'README.md',
pageId: 'markdown_viewer',
icon: Icons.description_outlined,
),
],
),
],
),
},
// 3. Register Page Builders
pageRegistry: {
'markdown_viewer': (context, args) => const Center(child: Text('README')),
},
),
),
);
}
}The WorkspaceConfig is built to be extremely flexible. For complex applications, it is highly recommended to dynamically generate your sidebar using backend-driven JSON schemas combined with a state manager (like flutter_bloc).
This approach easily enables Role-Based Access Control (RBAC).
By wrapping WorkspaceShell in a state listener, the shell will seamlessly update and automatically close restricted tabs when roles change!
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
// Listen to your Auth/Role State Manager
return BlocBuilder<RoleCubit, String>(
builder: (context, currentRole) {
return MaterialApp(
home: WorkspaceShell(
config: WorkspaceConfig(
// 1. Parse your backend JSON and filter by `currentRole`
activityBarItems: CustomParser.parseActivityBar(jsonSchema, currentRole),
sidebarViews: CustomParser.parseSidebars(jsonSchema, currentRole),
// 2. Only provide page builders the user has access to
pageRegistry: CustomParser.getPageRegistry(currentRole),
),
),
);
},
);
}
}- Discard Restricted Items: Overwrite your
CustomParserto check if a user has permission to see a JSON item. If not, don't instantiate theMenuItem. - Auto-Purge Tabs: Because
WorkspaceShellis deeply stateful, if the user's role changes, the shell will automatically purge any open tabs that no longer exist in the updatedpageRegistry. - Custom Backend Icons: Make use of the
iconWidgetparameter to parse custom backend icons (SVGs, Image Assets, custom Flutter code) instead of standardIconDatato ensure Flutter web compilation works smoothly with tree-shaking.
See the example/lib/main.dart source code to view a complete, production-ready implementation of dynamic JSON parsing and an interactive RBAC role toggle.
Check out the example directory for a complete, runnable sample application.
MIT
