Skip to content

Commit

Permalink
feat: Add sticky notes support to the new canvas (no-changelog) (n8n-…
Browse files Browse the repository at this point in the history
  • Loading branch information
alexgrozav authored Jul 15, 2024
1 parent 9302e33 commit cd24c71
Show file tree
Hide file tree
Showing 32 changed files with 653 additions and 147 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { action } from '@storybook/addon-actions';
import type { StoryFn } from '@storybook/vue3';
import N8nResizeableSticky from './ResizeableSticky.vue';

export default {
title: 'Atoms/ResizeableSticky',
component: N8nResizeableSticky,
argTypes: {
content: {
control: {
control: 'text',
},
},
height: {
control: {
control: 'number',
},
},
minHeight: {
control: {
control: 'number',
},
},
minWidth: {
control: {
control: 'number',
},
},
readOnly: {
control: {
control: 'Boolean',
},
},
width: {
control: {
control: 'number',
},
},
},
};

const methods = {
onInput: action('update:modelValue'),
onResize: action('resize'),
onResizeEnd: action('resizeend'),
onResizeStart: action('resizestart'),
};

const Template: StoryFn = (args, { argTypes }) => ({
setup: () => ({ args }),
props: Object.keys(argTypes),
components: {
N8nResizeableSticky,
},
template:
'<n8n-resizeable-sticky v-bind="args" @resize="onResize" @resizeend="onResizeEnd" @resizeStart="onResizeStart" @input="onInput"></n8n-resizeable-sticky>',
methods,
});

export const ResizeableSticky = Template.bind({});
ResizeableSticky.args = {
height: 160,
width: 150,
modelValue:
"## I'm a note \n**Double click** to edit me. [Guide](https://docs.n8n.io/workflows/sticky-notes/)",
minHeight: 80,
minWidth: 150,
readOnly: false,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<template>
<N8nResizeWrapper
:is-resizing-enabled="!readOnly"
:height="height"
:width="width"
:min-height="minHeight"
:min-width="minWidth"
:scale="scale"
:grid-size="gridSize"
@resizeend="onResizeEnd"
@resize="onResize"
@resizestart="onResizeStart"
>
<N8nSticky v-bind="stickyBindings" />
</N8nResizeWrapper>
</template>

<script lang="ts" setup>
import { computed, ref, useAttrs } from 'vue';
import N8nResizeWrapper, { type ResizeData } from '../N8nResizeWrapper/ResizeWrapper.vue';
import N8nSticky from '../N8nSticky/Sticky.vue';
import type { StickyProps } from '../N8nSticky/types';
import { defaultStickyProps } from '../N8nSticky/constants';
type ResizeableStickyProps = StickyProps & {
scale?: number;
gridSize?: number;
};
const props = withDefaults(defineProps<ResizeableStickyProps>(), {
...defaultStickyProps,
scale: 1,
gridSize: 20,
});
const emit = defineEmits<{
resize: [values: ResizeData];
resizestart: [];
resizeend: [];
}>();
const attrs = useAttrs();
const stickyBindings = computed(() => ({ ...props, ...attrs }));
const isResizing = ref(false);
const onResize = (values: ResizeData) => {
emit('resize', values);
};
const onResizeStart = () => {
isResizing.value = true;
emit('resizestart');
};
const onResizeEnd = () => {
isResizing.value = false;
emit('resizeend');
};
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import ResizeableSticky from './ResizeableSticky.vue';

export default ResizeableSticky;
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,7 @@ export const Sticky = Template.bind({});
Sticky.args = {
height: 160,
width: 150,
content:
"## I'm a note \n**Double click** to edit me. [Guide](https://docs.n8n.io/workflows/sticky-notes/)",
defaultText:
modelValue:
"## I'm a note \n**Double click** to edit me. [Guide](https://docs.n8n.io/workflows/sticky-notes/)",
minHeight: 80,
minWidth: 150,
Expand Down
128 changes: 38 additions & 90 deletions packages/design-system/src/components/N8nSticky/Sticky.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,98 +9,58 @@
:style="styles"
@keydown.prevent
>
<N8nResizeWrapper
:is-resizing-enabled="!readOnly"
:height="height"
:width="width"
:min-height="minHeight"
:min-width="minWidth"
:scale="scale"
:grid-size="gridSize"
@resizeend="onResizeEnd"
@resize="onResize"
@resizestart="onResizeStart"
<div v-show="!editMode" :class="$style.wrapper" @dblclick.stop="onDoubleClick">
<N8nMarkdown
theme="sticky"
:content="modelValue"
:with-multi-breaks="true"
@markdown-click="onMarkdownClick"
@update-content="onUpdateModelValue"
/>
</div>
<div
v-show="editMode"
:class="{ 'full-height': !shouldShowFooter, 'sticky-textarea': true }"
@click.stop
@mousedown.stop
@mouseup.stop
@keydown.esc="onInputBlur"
@keydown.stop
>
<div v-show="!editMode" :class="$style.wrapper" @dblclick.stop="onDoubleClick">
<N8nMarkdown
theme="sticky"
:content="modelValue"
:with-multi-breaks="true"
@markdown-click="onMarkdownClick"
@update-content="onUpdateModelValue"
/>
</div>
<div
v-show="editMode"
:class="{ 'full-height': !shouldShowFooter, 'sticky-textarea': true }"
@click.stop
@mousedown.stop
@mouseup.stop
@keydown.esc="onInputBlur"
@keydown.stop
>
<N8nInput
ref="input"
:model-value="modelValue"
type="textarea"
:rows="5"
@blur="onInputBlur"
@update:model-value="onUpdateModelValue"
@wheel="onInputScroll"
/>
</div>
<div v-if="editMode && shouldShowFooter" :class="$style.footer">
<N8nText size="xsmall" align="right">
<span v-html="t('sticky.markdownHint')"></span>
</N8nText>
</div>
</N8nResizeWrapper>
<N8nInput
ref="input"
:model-value="modelValue"
:name="inputName"
type="textarea"
:rows="5"
@blur="onInputBlur"
@update:model-value="onUpdateModelValue"
@wheel="onInputScroll"
/>
</div>
<div v-if="editMode && shouldShowFooter" :class="$style.footer">
<N8nText size="xsmall" align="right">
<span v-html="t('sticky.markdownHint')"></span>
</N8nText>
</div>
</div>
</template>

<script lang="ts" setup>
import { computed, ref, watch } from 'vue';
import N8nInput from '../N8nInput';
import N8nMarkdown from '../N8nMarkdown';
import N8nResizeWrapper, { type ResizeData } from '../N8nResizeWrapper/ResizeWrapper.vue';
import N8nText from '../N8nText';
import { useI18n } from '../../composables/useI18n';
import { defaultStickyProps } from './constants';
import type { StickyProps } from './types';
interface StickyProps {
modelValue?: string;
height?: number;
width?: number;
minHeight?: number;
minWidth?: number;
scale?: number;
gridSize?: number;
id?: string;
defaultText?: string;
editMode?: boolean;
readOnly?: boolean;
backgroundColor?: number | string;
}
const props = withDefaults(defineProps<StickyProps>(), {
height: 180,
width: 240,
minHeight: 80,
minWidth: 150,
scale: 1,
gridSize: 20,
id: '0',
editMode: false,
readOnly: false,
backgroundColor: 1,
});
const props = withDefaults(defineProps<StickyProps>(), defaultStickyProps);
const emit = defineEmits<{
edit: [editing: boolean];
'update:modelValue': [value: string];
'markdown-click': [link: string, e: Event];
resize: [values: ResizeData];
resizestart: [];
resizeend: [];
}>();
const { t } = useI18n();
Expand All @@ -115,6 +75,8 @@ const resWidth = computed((): number => {
return props.width < props.minWidth ? props.minWidth : props.width;
});
const inputName = computed(() => (props.id ? `${props.id}-input` : undefined));
const styles = computed((): { height: string; width: string } => ({
height: `${resHeight.value}px`,
width: `${resWidth.value}px`,
Expand Down Expand Up @@ -152,20 +114,6 @@ const onMarkdownClick = (link: string, event: Event) => {
emit('markdown-click', link, event);
};
const onResize = (values: ResizeData) => {
emit('resize', values);
};
const onResizeStart = () => {
isResizing.value = true;
emit('resizestart');
};
const onResizeEnd = () => {
isResizing.value = false;
emit('resizeend');
};
const onInputScroll = (event: WheelEvent) => {
// Pass through zoom events but hold regular scrolling
if (!event.ctrlKey && !event.metaKey) {
Expand Down
10 changes: 10 additions & 0 deletions packages/design-system/src/components/N8nSticky/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export const defaultStickyProps = {
height: 180,
width: 240,
minHeight: 80,
minWidth: 150,
id: '0',
editMode: false,
readOnly: false,
backgroundColor: 1,
};
12 changes: 12 additions & 0 deletions packages/design-system/src/components/N8nSticky/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export interface StickyProps {
modelValue?: string;
height?: number;
width?: number;
minHeight?: number;
minWidth?: number;
id?: string;
defaultText?: string;
editMode?: boolean;
readOnly?: boolean;
backgroundColor?: number | string;
}
1 change: 1 addition & 0 deletions packages/design-system/src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export { default as N8nResizeWrapper } from './N8nResizeWrapper';
export { default as N8nSelect } from './N8nSelect';
export { default as N8nSpinner } from './N8nSpinner';
export { default as N8nSticky } from './N8nSticky';
export { default as N8nResizeableSticky } from './N8nResizeableSticky';
export { default as N8nTabs } from './N8nTabs';
export { default as N8nTag } from './N8nTag';
export { default as N8nTags } from './N8nTags';
Expand Down
1 change: 1 addition & 0 deletions packages/editor-ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
"@vue-flow/controls": "^1.1.1",
"@vue-flow/core": "^1.33.5",
"@vue-flow/minimap": "^1.4.0",
"@vue-flow/node-resizer": "^1.4.0",
"@vueuse/components": "^10.11.0",
"@vueuse/core": "^10.11.0",
"axios": "1.6.7",
Expand Down
8 changes: 5 additions & 3 deletions packages/editor-ui/src/__tests__/data/canvas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { CanvasNodeRenderType } from '@/types';

export function createCanvasNodeData({
id = 'node',
name = 'Test Node',
type = 'test',
typeVersion = 1,
disabled = false,
Expand All @@ -21,13 +22,14 @@ export function createCanvasNodeData({
},
}: Partial<CanvasNodeData> = {}): CanvasNodeData {
return {
id,
name,
type,
typeVersion,
execution,
issues,
pinnedData,
runData,
id,
type,
typeVersion,
disabled,
inputs,
outputs,
Expand Down
Loading

0 comments on commit cd24c71

Please sign in to comment.