Skip to content

CodeLayout usage

Basic examples

It is recommended to place CodeLayout at the top-level component and set the width and height to fill the screen.

WARNING

This component is designed to fill the parent container. Please set position: relative style for the parent container and set a certain height, otherwise the component will not be able to calculate the height correctly and display properly.

To use CodeLayout, there are the following steps:

  1. Import Component.
  2. Define basic layout data: Basic layout data controls the size, position, and display status of several main parts.
  3. Define slots and content: In components, content is organized on a "panel" basis, so panel data needs to be added and rendered in the slots.

For example:

<template>
  <h1>Hello {{ msg }}</h1>
</template>

<script setup lang="ts">
import { ref } from 'vue';
const msg = ref<string>('world');
</script>

Panel operation

Definition:

  • Group: A group is a container that can contain multiple sub panels
  • Panel: Panel, the content is organized in units of "panels", and the panel is the basic unit that ultimately allows you to render the content. Users can drag, show/hide, and open/close each panel.

Taking the Explorer section of VSCode as an example, clicks on Explorer, there are also folders, outline, timeline, and so on inside,

So the Explorer is a group, and the Folders, Outline, and Timeline are panels.

You can add your panels to the components, or obtain panel instances for corresponding operations or settings.

To using the CodeLayout component, you need to first obtain its instance, and then call the method on the instance:

ts
import { CodeLayoutInstance } from 'vue-code-layout';

//Bind the codeLayoutInstance variable to the CodeLayout component through the ref attribute
const codeLayoutInstance = ref<CodeLayoutInstance>();

Get Root Group

As Introduce said, The component is divided into four major sections, and the component provides a method to obtain the root group:

ts
const primarySideBar = codeLayoutInstance.value.getRootGrid('primarySideBar'); 
const secondarySideBar = codeLayoutInstance.value.getRootGrid('secondarySideBar');
const bottomPanel = codeLayoutInstance.value.getRootGrid('bottomPanel');

Add Group/Panel

You can add groups to the root, for example, the following code adds a group titled "Explorer" to the first sidebar:

ts
const groupExplorer = codeLayout.value.addGroup({
  title: 'Explorer',
  tooltip: 'Explorer',
  name: 'explorer',
  badge: '2',
  iconLarge: () => h(IconFile),
}, 'primarySideBar');

After obtaining the group, you can add panels to the custom group or root group:

ts
groupExplorer.addPanel({
  title: 'VUE-CODE-LAYOUT',
  tooltip: 'vue-code-layout',
  name: 'explorer.file',
  noHide: true,
  startOpen: true,
  iconSmall: () => h(IconSearch),
  actions: [
    { 
      name: 'test',
      icon: () => h(IconSearch),
      onClick() {},
    },
    { 
      name: 'test2',
      icon: () => h(IconFile),
      onClick() {},
    },
  ]
});
bottomPanel.addPanel({
  title: 'TERMINAL',
  tooltip: 'Terminal',
  name: 'bottom.terminal',
  actions: [
    { 
      name: 'test',
      icon: () => h(IconSearch),
      onClick() {},
    },
    { 
      name: 'test2',
      icon: () => h(IconFile),
      onClick() {},
    },
  ]
});

Tip: Currently, CodeLayout does not support nested groups within groups (VSCode also does not have nested group functionality). When users drag and drop, nested groups will not be generated. Therefore, when using code to add, do not nest groups as it may cause problems.

Groups can only be nested up to one level (groups can only be generated under the root group).

Get panel instance

When adding a panel, the 'name' attribute must be guaranteed to be unique, so you can use name to query the added panel instances and change them:

ts
//Get the panel and modify the badge
const groupExplorer = codeLayout.value.getPanelByName('explorer')
groupExplorer.badge = '3';

Panel show, hide

The display and hiding of the panel can be controlled through the visible attribute on the instance.

ts
groupExplorer.visible = false;

Delete panel

ts
groupExplorer.removeSelfWithShrink(); //Delete oneself and trigger automatic shrinkage of the parent group (automatic shrinkage will merge empty groups)

Badge, Icon, Title, Actions

A panel supports the following configuration fields to control the display of some information, and its display position is shown in the figure:

Vertical: CodeLayoutTitle1

Horizontal: CodeLayoutTitle2

You can specify these properties during creation or modify them through instance properties after creation.

ts
const groupExplorer = codeLayout.value.addGroup({
  name: 'explorer',
  //Title Text
  title: 'Explorer',
  //Tooltips displayed when hovering the mouse
  tooltip: 'Explorer',
  //Badge, recommended within 2 digits
  badge: '2', 
  //Large icons (usually displayed in ActionBar)
  iconLarge: () => h(IconFile), 
  //Small icons (usually displayed at the top of the panel)
  iconSmall: () => h(IconFile), 
  //Custom actions, which will be displayed as buttons on the right side of the panel header
  actions: [
    { 
      name: 'test',
      icon: () => h(IconSearch),
      onClick() {},
    },
    { 
      name: 'test2',
      icon: () => h(IconFile),
      onClick() {},
    },
  ]
}, 'primarySideBar');

Drag control

By default, all panels can be dragged and dropped from one root group to another. To restrict this operation, you can use the following methods:

  • Set a panel to be non draggable.

    ts
    bottomGroup.addPanel({
      title: 'PORTS',
      tooltip: 'Ports',
      name: 'bottom.ports',
      draggable: false, //No dragging allowed
    });
  1. By using accept to limit the root groups that panels can be placed in, for example, the panel below is set to accept, which limits the panel to only be placed in the bottom panel root group.
ts
bottomGroup.addPanel({
  title: 'PORTS',
  tooltip: 'Ports',
  name: 'bottom.ports',
  startOpen: true,
  iconSmall: () => h(IconSearch),
  accept: [ 'bottomPanel' ], //limit
});
  1. Processing through custom callbacks

    By customizing callbacks, drag callbacks can be set in the basic configuration, and returning false in the callback indicates that drag is blocked.

    NameTypeExplain
    referenceCodeLayoutPanelThe panel instance that user attempts to place reference position
    referencePositionstringDrop position
    panelCodeLayoutPanelThe panel instance that the user is dragging
    dropTostringDrop target type
    ts
    const config = reactive<CodeLayoutConfig>({
      onDropToPanel(reference, referencePosition, panel, dropTo) {
        if (reference.name === 'explorer.file' && panel.name === 'explorer.outline') {
          return false;
        }
        return false
      },
    });

Saving and Loading Data

CodeLayout supports you to save the layout dragged by the user to JSON data, and then reload it from JSON data to restore the original layout after the next entry.

CodeLayout supports two events, canLoadLayout and canSaveLayout. In the event callback, the current component instance will be returned. You can perform load and save operations in the event callback, or at other times, you can freely control the load and save operations by calling the loadLayout and saveLayout functions on the component instance.

vue
<template>
  <CodeLayout 
    ref="codeLayout"
    :layout-config="config"
    style="height: 400px"
    @canLoadLayout="loadLayout"
    @canSaveLayout="saveLayout"
  />
</template>

<script lang="ts" setup>
import { ref, onMounted } from 'vue';
import type { CodeLayoutInstance } from 'vue-code-layout';

const codeLayout = ref<CodeLayoutInstance>();

//Load and save operations can be performed in event callbacks, which are triggered by default during component initialization and uninstallation
//The event will pass the component instance ref, which can be directly called, equivalent to codeLayout.value
function loadLayout(ref: CodeLayoutInstance) {
  //Load here
}
function saveLayout(ref: CodeLayoutInstance) {
  //Save here
}

//You can also load/save data by calling component instance methods at other custom times
onMounted(() => {
  codeLayout.value.loadLayout();
})
</script>

Save data

Save layout data by calling the saveLayout method.

At the same time, you should also save the basic layout data (CodeLayoutConfig), which defines the size of each basic group, whether to display it, basic layout settings, etc, To save this data, simply call the saveLayout function and save the config variable.

ts
import { toRaw, reactive } from 'vue';
import type { CodeLayoutConfig } from 'vue-code-layout';

const config = reactive<CodeLayoutConfig>({
  //...
});

const json = codeLayout.value.saveLayout();

localStorage.setItem('LayoutData', json);
localStorage.setItem('LayoutConfig', toRaw(config)); //Save basic layout data

Load data

The basic layout data only needs to be reloaded into variables after saving.

ts
import { toRaw, reactive } from 'vue';
import type { CodeLayoutConfig } from 'vue-code-layout';

//Load basic layout data
const config = reactive<CodeLayoutConfig>({
  //This is just an example. There are multiple methods to fill in the data, and you can use your preferred method
  ...JSON.parse(localStorage.getItem('LayoutConfig'))
});

Layout data only stores the basic position, size, and other information of each layout, and does not contain information that cannot be serialized (such as callback functions and icons). So you also need to fill in these data based on the panel name in the callback of loadLayout to instantiated the panel.

ts
const data = localStorage.getItem('LayoutData');
if (data) {
  //If load layout from data, need fill panel data
  codeLayout.value.loadLayout(JSON.parse(data), (panel) => {
    switch (panel.name) {
      case 'explorer':
        panel.title = 'Explorer';
        panel.tooltip = 'Explorer';
        panel.badge = '2';
        panel.iconLarge = () => h(IconFile);
        break;
      case 'search':
        panel.title = 'Search';
        panel.tooltip = 'Search';
        panel.iconLarge = () => h(IconSearch);
        break;
      case 'explorer.file':
        panel.title = 'VUE-CODE-LAYOUT';
        panel.tooltip = 'vue-code-layout';
        panel.actions = [
          { 
            name: 'test',
            icon: () => h(IconSearch),
            onClick() {},
          },
          { 
            name: 'test2',
            icon: () => h(IconFile),
            onClick() {},
          },
        ]
        panel.iconSmall = () => h(IconSearch);
        break; 
      case 'explorer.outline':
        panel.title = 'OUTLINE';
        panel.tooltip = 'Outline';
        panel.actions = [
          { 
            name: 'test',
            icon: () => h(IconSearch),
            onClick() {},
          },
          { 
            name: 'test2',
            icon: () => h(IconFile),
            onClick() {},
          },
        ]
        panel.iconSmall = () => h(IconSearch);
        break;
      case 'bottom.ports':
        panel.title = 'PORTS';
        panel.tooltip = 'Ports';
        panel.iconSmall = () => h(IconSearch);
        break;  
      case 'bottom.terminal':
        panel.title = 'TERMINAL';
        panel.tooltip = 'Terminal';
        panel.iconSmall = () => h(IconSearch);
        break;
    }
    return panel;
  });
} else {
  //No data, create new layout
  //...
}

Built-in main menu

Due to CodeLayout's dependence on menu functions, menu functions are integrated with CodeLayout, If your application requires a main menu, you can refer to the following examples to quickly configure the main menu, or you can render the menu yourself through the titleBarMenu slot.

The menu is based on vue3-context-menu, Please refer to its documentation for configuration.

vue
<template>
  <CodeLayout 
    ref="codeLayout"
    :layoutConfig="config"
    :mainMenuConfig="menuData"
    style="height: 400px"
  >
    <template #titleBarIcon>
      <img :src="logo" width="20px" style="margin:0 10px 0 13px">
    </template>
  </CodeLayout>
</template>

<script lang="ts" setup>
import { reactive } from 'vue';
import type { MenuOptions } from '@imengyu/vue3-context-menu';
import logo from '../../../examples/assets/images/logo.svg';

const config = reactive<CodeLayoutConfig>({
  primarySideBarSwitchWithActivityBar: true,
  primarySideBarPosition: 'left',
  primarySideBarWidth: 40,
  primarySideBarMinWidth: 170,
  activityBarPosition: 'side',
  secondarySideBarWidth: 20,
  secondarySideBarMinWidth: 170,
  bottomPanelHeight: 50,
  bottomPanelMinHeight: 10,
  bottomAlignment: 'center',
  panelHeaderHeight: 24,
  panelMinHeight: 150,
  titleBar: true,
  titleBarShowCustomizeLayout: true,
  activityBar: true,
  primarySideBar: true,
  secondarySideBar: false,
  bottomPanel: true,
  statusBar: true,
  menuBar: true,
  bottomPanelMaximize: false
});
const menuData : MenuOptions = {
  x: 0,
  y: 0,
  items: [
    {
      label: "File",
      children: [
        { label: "New" },
        { label: "Open" },
        { 
          label: "Open recent",
          children: [
            { label: "File 1...." },
            { label: "File 2...." },
            { label: "File 3...." },
            { label: "File 4...." },
            { label: "File 5...." },
          ],
        },
        { label: "Save", divided: true },
        { label: "Save as..." },
        { label: "Close" },
        { label: "Exit" },
      ],
    },
    {
      label: "Edit",
      children: [
        { label: "Undo" },
        { label: "Redo" },
        { label: "Cut", divided: true },
        { label: "Copy" },
        { label: "Find", divided: true },
        { label: "Replace" },
      ],
    },
    {
      label: "View",
      children: [
        { label: "Zoom in" },
        { label: "Zoom out" },
        { label: "Reset zoom" },
        { label: "Full screent", divided: true },
        { label: "Find", divided: true },
        { label: "Replace" },
      ],
    },
    {
      label: "Help",
      children: [
        { label: "About" },
      ],
    },
  ],
  zIndex: 3,
  minWidth: 230,
};
</script>

Other slots

CodeLayout are also provided some solts for your use:

CodeLayoutSlots

  • titleBarIcon: Title bar rendering icon position
  • titleBarMenu: Title bar rendering main menu position
  • titleBarCenter: Title bar center position
  • titleBarRight: Position on the right side of the title bar (VSCode places the close button here)
  • titleBarTop: Area above the title bar
  • titleBarBottom: The area at the bottom of the title bar, above the center area, where custom actions can be placed
  • activityBarBottom: At the bottom of the activity bar (where VSCode places the settings button)
  • centerArea: The central area of CenterArea, where SliptLayout or other editor core components can be placed
  • statusBar: Status Bar Position

TIP: Component unmont

Tip: Vue may unmont and recreate your components in the following two situations:

  • Users drag and drop a panel to another panel
  • In development mode, when you modify the code, HMR overloads

At this point, Vue may unmont and recreate your component, causing the component state to be lost. Therefore, you need to handle your own component and save the relevant state.

TIP

Tip: In development mode, when you modify the code, HMR overloading may also unmount CodeLayout. If you only add panels in the onMounted callback, it will not be triggered again, so panel data within the component will be lost. To solve this problem, you can move the logic of add panels in the onMounted callback to the canLoadLayout event callback in CodeLayout to recreate the data.

Released under the MIT License.