Skip to content

Commit

Permalink
feat(editor): Main navigation redesign (n8n-io#4144)
Browse files Browse the repository at this point in the history
* refactor(editor): N8N-4540 Main navigation layout rework (n8n-io#4060)

* ✨ Implemented new editor layout using css grid

* ✨ Reworking main navigation layout, migrating some styling to css modules

* ✨ Reworking main sidebar layout and responsiveness

* 💄 Minor type update

* ✨ Updated editor grid layout so empty cells are collapsed (`fit-content`), fixed updates menu items styling

* ✨ Implemented new user area look & feel in main sidebar

* 💄 Adjusting sidebar bottom padding when user area is not shown

* 💄 CSS cleanup/refactor + minor vue refactoring

* ✨ Fixing overscoll issue in chrome and scrolling behaviour of the content view

* 👌 Addressing review feedback

* ✨ Added collapsed and expanded versions of n8n logo

* ✨ Updating infinite scrolling in templates view to work with the new layout

* 💄 Updating main sidebar expanded width and templates view left margin

* 💄 Updating main content height

* 💄 Adding global styles for scrollable views with centered content, minor updates to user area

* ✨ Updating zoomToFit logic, lasso select box position and new nodes positioning

* ✨ Fixing new node drop position now that mouse detection has been adjusted

* 👌 Updating templates view scroll to top logic and responsive padding, aligning menu items titles

* 💄 Moving template layout style from global css class to component level

* ✨ Moved 'Workflows'  menu to node view header. Added new dropdown component for user area and the new WF menu

* 💄 Updating disabled states in new WF menu

* 💄 Initial stab at new sidebar styling

* ✨ Finished main navigation restyling

* ✨ Updating `zoomToFit` and centering logic

* ✨ Adding updates menu item to settings sidebar

* 💄 Adding updates item to the settings sidebar and final touches on main sidebar style

* 💄 Removing old code & refactoring

* 💄 Minor CSS tweaks

* 💄 Opening credentials modal on sidebar menu item click. Minor CSS updates

* 💄 Updating sidebar expand/collapse animation

* 💄 Few more refinements of sidebar animation

* 👌 Addressing code review comments

* ✨ Moved ActionDropdown component to design system

* 👌 Fixing bugs reported during code review and testing

* 👌 Addressing design review comments for the new sidebar

* ✔️ Updating `N8nActionDropdown` component tests

* ✨ Remembering scroll position when going back to templates list

* ✨ Updating zoomToFit logic to account for footer content

* 👌 Addressing latest sidebar review comments

* 👌 Addressing main sidebar product review comments

* 💄 Updating css variable names after vite merge

* ✔️ Fixing linting errors in the design system

* ✔️ Fixing `element-ui` type import

* 👌 Addressing the code review comments.

* ✨ Adding link to new credentials view, removed old modal

* 💄 Updating credentials view responsiveness and route highlight handling

* 💄 Adding highlight to workflows submenu when on new workflow page

* 💄 Updated active submenu text color
  • Loading branch information
MiloradFilipovic authored Sep 26, 2022
1 parent 72c59a0 commit c511c68
Show file tree
Hide file tree
Showing 37 changed files with 1,341 additions and 911 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import N8nActionDropdown from "./ActionDropdown.vue";
import { StoryFn } from '@storybook/vue';

export default {
title: 'Atoms/ActionDropdown',
component: N8nActionDropdown,
argTypes: {
placement: {
control: {
type: 'select',
options: ['top', 'top-end', 'top-start', 'bottom', 'bottom-end', 'bottom-start'],
},
},
activatorIcon: {
control: {
type: 'text',
},
},
trigger: {
control: {
type: 'select',
options: ['click', 'hover'],
},
},
},
};

const template: StoryFn = (args, { argTypes }) => ({
props: Object.keys(argTypes),
components: {
N8nActionDropdown,
},
template: `<n8n-action-dropdown v-bind="$props" />`,
});

export const defaultActionDropdown = template.bind({});
defaultActionDropdown.args = {
items: [
{
id: 'item1',
label: 'Action 1',
},
{
id: 'item2',
label: 'Action 2',
},
],
};

export const customStyling = template.bind({});
customStyling.args = {
activatorIcon: 'bars',
items: [
{
id: 'item1',
label: 'Action 1',
icon: 'thumbs-up',
},
{
id: 'item2',
label: 'Action 2',
icon: 'thumbs-down',
disabled: true,
},
{
id: 'item3',
label: 'Action 3',
icon: 'heart',
divided: true,
},
],
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
<template>
<div :class="['action-dropdown-container', $style.actionDropdownContainer]">
<el-dropdown :placement="placement" :trigger="trigger" @command="onSelect">
<div :class="$style.activator">
<n8n-icon :icon="activatorIcon"/>
</div>
<el-dropdown-menu slot="dropdown" :class="$style.userActionsMenu">
<el-dropdown-item
v-for="item in items"
:key="item.id"
:command="item.id"
:disabled="item.disabled"
:divided="item.divided"
>
<div :class="{
[$style.itemContainer]: true,
[$style.hasCustomStyling]: item.customClass !== undefined,
[item.customClass]: item.customClass !== undefined,
}">
<span v-if="item.icon" :class="$style.icon">
<n8n-icon :icon="item.icon"/>
</span>
<span :class="$style.label">
{{ item.label }}
</span>
</div>
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
</template>

<script lang="ts">
import Vue, { PropType } from "vue";
import ElDropdown from 'element-ui/lib/dropdown';
import ElDropdownMenu from 'element-ui/lib/dropdown-menu';
import ElDropdownItem from 'element-ui/lib/dropdown-item';
import N8nIcon from '../N8nIcon';
interface IActionDropdownItem {
id: string;
label: string;
icon?: string;
divided?: boolean;
disabled?: boolean;
customClass?: string;
}
// This component is visually similar to the ActionToggle component
// but it offers more options when it comes to dropdown items styling
// (supports icons, separators, custom styling and all options provided
// by Element UI dropdown component).
// It can be used in different parts of editor UI while ActionToggle
// is designed to be used in card components.
export default Vue.extend({
name: 'n8n-action-dropdown',
components: {
ElDropdownMenu, // eslint-disable-line @typescript-eslint/no-unsafe-assignment
ElDropdown, // eslint-disable-line @typescript-eslint/no-unsafe-assignment
ElDropdownItem, // eslint-disable-line @typescript-eslint/no-unsafe-assignment
N8nIcon,
},
props: {
items: {
type: Array as PropType<IActionDropdownItem[]>,
required: true,
},
placement: {
type: String,
default: 'bottom',
validator: (value: string): boolean =>
['top', 'top-end', 'top-start', 'bottom', 'bottom-end', 'bottom-start'].includes(value),
},
activatorIcon: {
type: String,
default: 'ellipsis-v',
},
trigger: {
type: String,
default: 'click',
validator: (value: string): boolean =>
['click', 'hover'].includes(value),
},
},
methods: {
onSelect(action: string) : void {
this.$emit('select', action);
},
},
});
</script>

<style lang="scss" module>
.activator {
cursor: pointer;
padding: var(--spacing-2xs);
margin: 0;
border-radius: var(--border-radius-base);
line-height: normal !important;
svg {
position: static !important;
}
&:hover {
background-color: var(--color-background-base);
color: initial !important;
}
}
.itemContainer {
display: flex;
}
.icon {
text-align: center;
margin-right: var(--spacing-2xs);
svg { width: 1.2em !important; }
}
:global(li.is-disabled) {
.hasCustomStyling {
color: inherit !important;
}
}
</style>
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { render } from '@testing-library/vue';
import N8nActionDropdown from '../ActionDropdown.vue';

describe('components', () => {
describe('N8nActionDropdown', () => {
it('should render default styling correctly', () => {
const wrapper = render(N8nActionDropdown, {
props: {
items: [
{
id: 'item1',
label: 'Action 1',
},
{
id: 'item2',
label: 'Action 2',
},
],
},
stubs: ['n8n-icon', 'el-dropdown', 'el-dropdown-menu', 'el-dropdown-item'],
});
expect(wrapper.html()).toMatchSnapshot();
});
it('should render custom styling correctly', () => {
const wrapper = render(N8nActionDropdown, {
props: {
items: [
{
id: 'item1',
label: 'Action 1',
icon: 'thumbs-up',
},
{
id: 'item2',
label: 'Action 2',
icon: 'thumbs-down',
disabled: true,
},
{
id: 'item3',
label: 'Action 3',
icon: 'heart',
divided: true,
},
],
},
stubs: ['n8n-icon', 'el-dropdown', 'el-dropdown-menu', 'el-dropdown-item'],
});
expect(wrapper.html()).toMatchSnapshot();
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Vitest Snapshot v1

exports[`components > N8nActionDropdown > should render custom styling correctly 1`] = `
"<div class=\\"action-dropdown-container\\">
<el-dropdown-stub trigger=\\"click\\" size=\\"\\" hideonclick=\\"true\\" placement=\\"bottom\\" visiblearrow=\\"true\\" showtimeout=\\"250\\" hidetimeout=\\"150\\" tabindex=\\"0\\">
<div class=\\"_activator_lf4ng_1\\">
<n8n-icon-stub icon=\\"ellipsis-v\\" size=\\"medium\\"></n8n-icon-stub>
</div>
<el-dropdown-menu-stub transformorigin=\\"true\\" placement=\\"bottom\\" boundariespadding=\\"5\\" offset=\\"0\\" visiblearrow=\\"true\\" arrowoffset=\\"0\\" appendtobody=\\"true\\" popperoptions=\\"[object Object]\\">
<el-dropdown-item-stub command=\\"item1\\">
<div class=\\"_itemContainer_lf4ng_16\\"><span class=\\"_icon_lf4ng_20\\"><n8n-icon-stub icon=\\"thumbs-up\\" size=\\"medium\\"></n8n-icon-stub></span><span> Action 1 </span></div>
</el-dropdown-item-stub>
<el-dropdown-item-stub command=\\"item2\\" disabled=\\"true\\">
<div class=\\"_itemContainer_lf4ng_16\\"><span class=\\"_icon_lf4ng_20\\"><n8n-icon-stub icon=\\"thumbs-down\\" size=\\"medium\\"></n8n-icon-stub></span><span> Action 2 </span></div>
</el-dropdown-item-stub>
<el-dropdown-item-stub command=\\"item3\\" divided=\\"true\\">
<div class=\\"_itemContainer_lf4ng_16\\"><span class=\\"_icon_lf4ng_20\\"><n8n-icon-stub icon=\\"heart\\" size=\\"medium\\"></n8n-icon-stub></span><span> Action 3 </span></div>
</el-dropdown-item-stub>
</el-dropdown-menu-stub>
</el-dropdown-stub>
</div>"
`;
exports[`components > N8nActionDropdown > should render default styling correctly 1`] = `
"<div class=\\"action-dropdown-container\\">
<el-dropdown-stub trigger=\\"click\\" size=\\"\\" hideonclick=\\"true\\" placement=\\"bottom\\" visiblearrow=\\"true\\" showtimeout=\\"250\\" hidetimeout=\\"150\\" tabindex=\\"0\\">
<div class=\\"_activator_lf4ng_1\\">
<n8n-icon-stub icon=\\"ellipsis-v\\" size=\\"medium\\"></n8n-icon-stub>
</div>
<el-dropdown-menu-stub transformorigin=\\"true\\" placement=\\"bottom\\" boundariespadding=\\"5\\" offset=\\"0\\" visiblearrow=\\"true\\" arrowoffset=\\"0\\" appendtobody=\\"true\\" popperoptions=\\"[object Object]\\">
<el-dropdown-item-stub command=\\"item1\\">
<div class=\\"_itemContainer_lf4ng_16\\">
<!----><span> Action 1 </span></div>
</el-dropdown-item-stub>
<el-dropdown-item-stub command=\\"item2\\">
<div class=\\"_itemContainer_lf4ng_16\\">
<!----><span> Action 2 </span></div>
</el-dropdown-item-stub>
</el-dropdown-menu-stub>
</el-dropdown-stub>
</div>"
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import N8nActionDropdown from './ActionDropdown.vue';
export default N8nActionDropdown;
2 changes: 1 addition & 1 deletion packages/design-system/src/css/reset.scss
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ html {
body {
height: 100%;
width: 100%;
overscroll-behavior-x: none;
overscroll-behavior: none;
line-height: 1;
font-size: var(--font-size-m);
font-weight: var(--font-weight-regular);
Expand Down
2 changes: 2 additions & 0 deletions packages/design-system/src/plugins/n8nComponents.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import Vue from 'vue';
import N8nActionBox from '../components/N8nActionBox';
import N8nActionDropdown from '../components/N8nActionDropdown';
import N8nActionToggle from '../components/N8nActionToggle';
import N8nAvatar from '../components/N8nAvatar';
import N8nBadge from "../components/N8nBadge";
Expand Down Expand Up @@ -46,6 +47,7 @@ export default {
install: (app: typeof Vue, options?: {}) => {
app.component('n8n-info-accordion', N8nInfoAccordion);
app.component('n8n-action-box', N8nActionBox);
app.component('n8n-action-dropdown', N8nActionDropdown);
app.component('n8n-action-toggle', N8nActionToggle);
app.component('n8n-avatar', N8nAvatar);
app.component('n8n-badge', N8nBadge);
Expand Down
Binary file modified packages/editor-ui/public/favicon.ico
Binary file not shown.
3 changes: 3 additions & 0 deletions packages/editor-ui/public/n8n-logo-collapsed.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions packages/editor-ui/public/n8n-logo-expanded.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit c511c68

Please sign in to comment.