feat: Add sticky notes support to the new canvas (no-changelog) (#10031)

This commit is contained in:
Alex Grozav
2024-07-15 13:00:52 +03:00
committed by GitHub
parent 9302e33d55
commit cd24c71a9e
32 changed files with 653 additions and 147 deletions

View File

@@ -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,
};

View File

@@ -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>

View File

@@ -0,0 +1,3 @@
import ResizeableSticky from './ResizeableSticky.vue';
export default ResizeableSticky;

View File

@@ -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,

View File

@@ -9,52 +9,40 @@
: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>
@@ -62,45 +50,17 @@
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();
@@ -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`,
@@ -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) {

View File

@@ -0,0 +1,10 @@
export const defaultStickyProps = {
height: 180,
width: 240,
minHeight: 80,
minWidth: 150,
id: '0',
editMode: false,
readOnly: false,
backgroundColor: 1,
};

View File

@@ -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;
}

View File

@@ -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';