mirror of
https://github.com/n8n-io/n8n.git
synced 2025-02-02 07:01:30 -08:00
refactor tabs
This commit is contained in:
parent
0bb3c6498d
commit
4344cc67a8
|
@ -0,0 +1,54 @@
|
|||
import N8nTabs from './Tabs.vue';
|
||||
|
||||
import { action } from '@storybook/addon-actions';
|
||||
|
||||
export default {
|
||||
title: 'Atoms/Tabs',
|
||||
component: N8nTabs,
|
||||
argTypes: {
|
||||
},
|
||||
parameters: {
|
||||
backgrounds: { default: '--color-background-xlight' },
|
||||
},
|
||||
};
|
||||
|
||||
const methods = {
|
||||
onInput: action('input'),
|
||||
};
|
||||
|
||||
const Template = (args, { argTypes }) => ({
|
||||
props: Object.keys(argTypes),
|
||||
components: {
|
||||
N8nTabs,
|
||||
},
|
||||
template:
|
||||
`<n8n-tabs v-model="val" v-bind="$props" @input="onInput">
|
||||
</n8n-tabs>`,
|
||||
methods,
|
||||
data() {
|
||||
return {
|
||||
val: '',
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export const Example = Template.bind({});
|
||||
Example.args = {
|
||||
options: [
|
||||
{
|
||||
label: 'Test',
|
||||
value: 'test',
|
||||
},
|
||||
{
|
||||
label: 'Github',
|
||||
value: 'github',
|
||||
href: 'https://github.com/',
|
||||
},
|
||||
{
|
||||
label: 'Settings',
|
||||
value: 'settings',
|
||||
icon: 'cog',
|
||||
align: 'right',
|
||||
},
|
||||
],
|
||||
};
|
99
packages/design-system/src/components/N8nTabs/Tabs.vue
Normal file
99
packages/design-system/src/components/N8nTabs/Tabs.vue
Normal file
|
@ -0,0 +1,99 @@
|
|||
<template>
|
||||
<div :class="$style.tabs">
|
||||
<div v-for="option in options" :key="option.value" :class="{ [$style.alignRight]: option.align === 'right' }">
|
||||
<a
|
||||
v-if="option.href"
|
||||
target="_blank"
|
||||
:href="option.href"
|
||||
:class="[$style.link, $style.tab]"
|
||||
@click="handleTabClick"
|
||||
>
|
||||
<div>
|
||||
{{ option.label }}
|
||||
<span :class="$style.external"><n8n-icon icon="external-link-alt" size="small" /></span>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<div
|
||||
v-else
|
||||
:class="{ [$style.tab]: true, [$style.activeTab]: value === option.value }"
|
||||
@click="() => handleTabClick(option.value)"
|
||||
>
|
||||
<n8n-icon v-if="option.icon" :icon="option.icon" size="small" />
|
||||
<span v-if="option.label">{{ option.label }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import N8nIcon from '../N8nIcon';
|
||||
|
||||
export default Vue.extend({
|
||||
name: 'N8nTabs',
|
||||
components: {
|
||||
N8nIcon,
|
||||
},
|
||||
props: {
|
||||
value: {
|
||||
type: String,
|
||||
},
|
||||
options: {
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
handleTabClick(tab: string) {
|
||||
this.$emit('input', tab);
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
<style lang="scss" module>
|
||||
.tabs {
|
||||
color: var(--color-text-base);
|
||||
font-weight: var(--font-weight-bold);
|
||||
display: flex;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.tab {
|
||||
display: block;
|
||||
padding: 0 var(--spacing-s) var(--spacing-2xs) var(--spacing-s);
|
||||
padding-bottom: var(--spacing-2xs);
|
||||
font-size: var(--font-size-s);
|
||||
cursor: pointer;
|
||||
&:hover {
|
||||
color: var(--color-primary);
|
||||
}
|
||||
}
|
||||
|
||||
.activeTab {
|
||||
color: var(--color-primary);
|
||||
border-bottom: var(--color-primary) 2px solid;
|
||||
}
|
||||
|
||||
.alignRight {
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.link {
|
||||
cursor: pointer;
|
||||
color: var(--color-text-base);
|
||||
|
||||
&:hover {
|
||||
color: var(--color-primary);
|
||||
|
||||
.external {
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.external {
|
||||
display: none;
|
||||
}
|
||||
|
||||
</style>
|
3
packages/design-system/src/components/N8nTabs/index.js
Normal file
3
packages/design-system/src/components/N8nTabs/index.js
Normal file
|
@ -0,0 +1,3 @@
|
|||
import N8nTabs from './Tabs.vue';
|
||||
|
||||
export default N8nTabs;
|
|
@ -58,6 +58,7 @@ import N8nSelect from './N8nSelect';
|
|||
import N8nSpinner from './N8nSpinner';
|
||||
import N8nSquareButton from './N8nSquareButton';
|
||||
import N8nTags from './N8nTags';
|
||||
import N8nTabs from './N8nTabs';
|
||||
import N8nTag from './N8nTag';
|
||||
import N8nText from './N8nText';
|
||||
import N8nTooltip from './N8nTooltip';
|
||||
|
@ -92,6 +93,7 @@ export {
|
|||
N8nSelect,
|
||||
N8nSpinner,
|
||||
N8nSquareButton,
|
||||
N8nTabs,
|
||||
N8nTags,
|
||||
N8nTag,
|
||||
N8nText,
|
||||
|
|
|
@ -1,32 +1,23 @@
|
|||
<template>
|
||||
<div :class="$style.tabs">
|
||||
<div
|
||||
:class="{ [$style.activeTab]: value === 'params' }"
|
||||
@click="() => handleTabClick('params')"
|
||||
>
|
||||
{{ $locale.baseText('nodeSettings.parameters') }}
|
||||
</div>
|
||||
|
||||
<a
|
||||
v-if="documentationUrl"
|
||||
target="_blank"
|
||||
:href="documentationUrl"
|
||||
:class="$style.docsTab"
|
||||
@click="onDocumentationUrlClick"
|
||||
>
|
||||
<div>
|
||||
{{ $locale.baseText('nodeSettings.docs') }}
|
||||
<font-awesome-icon :class="$style.external" icon="external-link-alt" size="sm" />
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<div
|
||||
:class="{ [$style.settingsTab]: true, [$style.activeTab]: value === 'settings' }"
|
||||
@click="() => handleTabClick('settings')"
|
||||
>
|
||||
<font-awesome-icon icon="cog" />
|
||||
</div>
|
||||
</div>
|
||||
<n8n-tabs
|
||||
:options="[
|
||||
{
|
||||
label: $locale.baseText('nodeSettings.parameters'),
|
||||
value: 'params'
|
||||
},
|
||||
{
|
||||
label: $locale.baseText('nodeSettings.docs'),
|
||||
value: 'docs',
|
||||
href: documentationUrl,
|
||||
},
|
||||
{
|
||||
icon: 'cog',
|
||||
value: 'settings',
|
||||
align: 'right',
|
||||
}]"
|
||||
:value="value"
|
||||
@input="onTabSelect"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
|
@ -65,64 +56,19 @@ export default mixins(
|
|||
},
|
||||
},
|
||||
methods: {
|
||||
onDocumentationUrlClick () {
|
||||
if (this.nodeType) {
|
||||
onTabSelect(tab: string) {
|
||||
if (tab === 'docs' && this.nodeType) {
|
||||
this.$externalHooks().run('dataDisplay.onDocumentationUrlClick', { nodeType: this.nodeType as INodeTypeDescription, documentationUrl: this.documentationUrl });
|
||||
}
|
||||
},
|
||||
handleTabClick(tab: string) {
|
||||
this.$emit('input', tab);
|
||||
|
||||
if(tab === 'settings' && this.nodeType) {
|
||||
this.$telemetry.track('User viewed node settings', { node_type: (this.nodeType as INodeTypeDescription).name, workflow_id: this.$store.getters.workflowId });
|
||||
}
|
||||
|
||||
if (tab === 'settings' || tab === 'params') {
|
||||
this.$emit('input', tab);
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
<style lang="scss" module>
|
||||
.tabs {
|
||||
color: var(--color-text-base);
|
||||
font-weight: var(--font-weight-bold);
|
||||
display: flex;
|
||||
width: 100%;
|
||||
|
||||
> * {
|
||||
padding: 0 var(--spacing-s) var(--spacing-2xs) var(--spacing-s);
|
||||
padding-bottom: var(--spacing-2xs);
|
||||
font-size: var(--font-size-s);
|
||||
cursor: pointer;
|
||||
&:hover {
|
||||
color: var(--color-primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.activeTab {
|
||||
color: var(--color-primary);
|
||||
border-bottom: var(--color-primary) 2px solid;
|
||||
}
|
||||
|
||||
.settingsTab {
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.docsTab {
|
||||
cursor: pointer;
|
||||
color: var(--color-text-base);
|
||||
|
||||
&:hover {
|
||||
color: var(--color-primary);
|
||||
|
||||
.external {
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.external {
|
||||
display: none;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
|
|
@ -30,22 +30,18 @@
|
|||
<!-- <n8n-text :bold="true" v-if="maxOutputIndex > 0">
|
||||
| {{ $locale.baseText('runData.output') }}:
|
||||
</n8n-text> -->
|
||||
<!-- <span class="opts" v-if="maxOutputIndex > 0" >
|
||||
<n8n-select size="mini" v-model="outputIndex" @click.stop>
|
||||
<n8n-option v-for="option in (maxOutputIndex + 1)" :label="getOutputName(option-1)" :value="option -1" :key="option">
|
||||
</n8n-option>
|
||||
</n8n-select>
|
||||
</span> -->
|
||||
|
||||
<!-- <n8n-text :bold="true" v-if="maxRunIndex > 0">
|
||||
| {{ $locale.baseText('runData.dataOfExecution') }}:
|
||||
</n8n-text> -->
|
||||
<span class="opts">
|
||||
|
||||
|
||||
<!-- <span class="opts">
|
||||
<n8n-select v-if="maxRunIndex > 0" size="mini" v-model="runIndex" @click.stop>
|
||||
<n8n-option v-for="option in (maxRunIndex + 1)" :label="option + '/' + (maxRunIndex+1)" :value="option-1" :key="option">
|
||||
</n8n-option>
|
||||
</n8n-select>
|
||||
</span>
|
||||
</span> -->
|
||||
</div>
|
||||
|
||||
<div v-if="!hasRunError" @click.stop>
|
||||
|
@ -76,7 +72,10 @@
|
|||
</div>
|
||||
|
||||
<div>
|
||||
<n8n-text v-if="hasNodeRun && dataCount > 0">
|
||||
<el-tabs v-model="outputIndex" v-if="maxOutputIndex > 0">
|
||||
<el-tab-pane v-for="option in (maxOutputIndex + 1)" :label="getOutputName(option-1)" :value="option -1" :key="option"></el-tab-pane>
|
||||
</el-tabs>
|
||||
<n8n-text v-else-if="hasNodeRun && dataCount > 0">
|
||||
{{ dataCount }} {{ $locale.baseText(dataCount === 1 ? 'node.output.item' : 'node.output.items') }}
|
||||
</n8n-text>
|
||||
</div>
|
||||
|
|
|
@ -64,6 +64,7 @@ import {
|
|||
N8nRadioButtons,
|
||||
N8nSelect,
|
||||
N8nSpinner,
|
||||
N8nTabs,
|
||||
N8nFormInputs,
|
||||
N8nFormBox,
|
||||
N8nSquareButton,
|
||||
|
@ -101,6 +102,7 @@ Vue.use(N8nSpinner);
|
|||
Vue.use(N8nRadioButtons);
|
||||
Vue.component('n8n-square-button', N8nSquareButton);
|
||||
Vue.use(N8nTags);
|
||||
Vue.component('n8n-tabs', N8nTabs);
|
||||
Vue.use(N8nTag);
|
||||
Vue.component('n8n-text', N8nText);
|
||||
Vue.use(N8nTooltip);
|
||||
|
|
Loading…
Reference in a new issue