Skip to content

Commit

Permalink
Merge pull request #36 from nethesis/components-fixes
Browse files Browse the repository at this point in the history
Add NeTabs component and various fixes
  • Loading branch information
andre8244 authored Apr 12, 2024
2 parents ed3d449 + 02568f2 commit fef3cf9
Show file tree
Hide file tree
Showing 10 changed files with 216 additions and 19 deletions.
1 change: 1 addition & 0 deletions src/components/NeBadge.vue
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ function onIconClick() {
<template v-if="icon">
<button
v-if="iconClickable"
type="button"
:class="[iconPosition == 'right' ? 'order-1' : '', iconButtonClasses, 'flex', 'rounded']"
@click="onIconClick"
>
Expand Down
15 changes: 12 additions & 3 deletions src/components/NeCombobox.vue
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,13 @@ const filteredOptions = computed(() => {
}

let results = allOptions.value.filter((option: NeComboboxOption) => {
return option.label.trim().toLowerCase().includes(query.value.trim().toLowerCase())
return (
// search in option label
option.label.trim().toLowerCase().includes(query.value.trim().toLowerCase()) ||
// search in option description
(option.description &&
option.description.trim().toLowerCase().includes(query.value.trim().toLowerCase()))
)
})

// user input
Expand Down Expand Up @@ -255,10 +261,13 @@ function selectMultipleOptionsFromModelValue() {
const selectedList: NeComboboxOption[] = []

for (const selectedOption of props.modelValue as NeComboboxOption[]) {
const optionFound = props.options.find((option) => option.id === selectedOption.id)
const optionFound = allOptions.value.find((option) => option.id === selectedOption.id)

if (optionFound) {
selectedList.push(optionFound)
} else if (props.acceptUserInput) {
userInputOptions.value.push(selectedOption)
selectedList.push(selectedOption)
}
}

Expand All @@ -282,7 +291,7 @@ function removeFromSelection(optionToRemove: NeComboboxOption) {
)
}

// detect clic outside to close the options list
// detect click outside to close the options list
onClickOutside(comboboxRef, () => onClickOutsideCombobox())
</script>

Expand Down
9 changes: 6 additions & 3 deletions src/components/NeInlineNotification.vue
Original file line number Diff line number Diff line change
Expand Up @@ -179,9 +179,12 @@ const closeIconKindStyle: { [index: string]: string } = {
</button>
<button
v-if="secondaryButtonLabel"
:class="`ml-3 rounded-md px-2 py-1.5 text-sm font-medium transition-colors duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2 ${
buttonsKindStyle[props.kind as string]
}`"
:class="[
`rounded-md px-2 py-1.5 text-sm font-medium transition-colors duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2 ${
buttonsKindStyle[props.kind as string]
}`,
{ 'ml-3': primaryButtonLabel }
]"
type="button"
@click="emit('secondaryClick')"
>
Expand Down
20 changes: 19 additions & 1 deletion src/components/NeLink.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,28 @@
Copyright (C) 2024 Nethesis S.r.l.
SPDX-License-Identifier: GPL-3.0-or-later
-->
<script lang="ts" setup>
defineProps({
// useful on inverted backgrounds (e.g. inside a tooltip)
invertedTheme: {
type: Boolean,
default: false
}
})

const standardThemeStyle =
'text-primary-700 hover:text-primary-800 dark:text-primary-300 dark:hover:text-primary-200'

const invertedThemeStyle =
'text-primary-300 hover:text-primary-200 dark:text-primary-700 dark:hover:text-primary-800'
</script>
<template>
<a
rel="noreferrer"
class="cursor-pointer text-primary-700 hover:text-primary-800 dark:text-primary-300 dark:hover:text-primary-200"
:class="[
'cursor-pointer font-medium hover:underline',
invertedTheme ? invertedThemeStyle : standardThemeStyle
]"
>
<slot />
</a>
Expand Down
6 changes: 3 additions & 3 deletions src/components/NeRadioSelection.vue
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,9 @@ const cardClasses: Record<RadioCardSize, string> = {
}

const iconClasses: Record<RadioCardSize, string> = {
md: 'h-7 w-7 pr-4',
lg: 'h-10 w-10 pr-5',
xl: 'h-12 w-12 pr-6'
md: 'h-7 w-7 pr-2',
lg: 'h-10 w-10 pr-3',
xl: 'h-12 w-12 pr-5'
}

const textClasses: Record<RadioCardSize, string> = {
Expand Down
107 changes: 107 additions & 0 deletions src/components/NeTabs.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
<!--
Copyright (C) 2024 Nethesis S.r.l.
SPDX-License-Identifier: GPL-3.0-or-later
-->

<script setup lang="ts">
import { ref, onMounted, watch } from 'vue'

export interface Tab {
name: string
label: string
}

export interface Props {
tabs: Tab[]
selected?: string
srSelectTabLabel?: string
srTabsLabel?: string
}

const props = withDefaults(defineProps<Props>(), {
tabs: () => [],
selected: '',
srSelectTabLabel: 'Select a tab',
srTabsLabel: 'Tabs'
})

let currentTab = ref('')

onMounted(() => {
selectTabFromSelectedProp()
})

watch(currentTab, () => {
emit('selectTab', currentTab.value)
})

watch(
() => [props.selected],
() => {
selectTabFromSelectedProp()
}
)

function selectTabFromSelectedProp() {
let selectedTab = props.tabs[0]

if (props.selected) {
let selectedTabFound = props.tabs.find((tab: any) => tab.name === props.selected)

if (selectedTabFound) {
selectedTab = selectedTabFound
}
}
currentTab.value = selectedTab.name
}

function selectTab(tabName: any) {
currentTab.value = tabName
}

const emit = defineEmits(['selectTab'])
</script>

<template>
<div>
<!-- mobile tabs -->
<div class="sm:hidden">
<label for="tabs_select" class="sr-only">{{ srSelectTabLabel }}</label>
<select
id="tabs_select"
v-model="currentTab"
name="tabs_select"
class="block w-full rounded-md border-gray-300 bg-white py-2 pl-3 pr-10 text-base text-gray-700 focus:border-primary-500 focus:outline-none focus:ring-primary-500 dark:border-gray-700 dark:bg-gray-950 dark:text-gray-50 dark:focus:border-primary-500 dark:focus:ring-primary-500 sm:text-sm"
>
<option
v-for="tab in props.tabs"
:key="tab.name"
:selected="currentTab === tab.name"
:value="tab.name"
>
{{ tab.label }}
</option>
</select>
</div>
<!-- desktop tabs -->
<div class="hidden sm:block">
<div class="border-b border-gray-200 dark:border-gray-700">
<nav class="-mb-px flex space-x-8" :aria-label="srTabsLabel">
<a
v-for="tab in props.tabs"
:key="tab.name"
:class="[
currentTab === tab.name
? 'border-primary-600 text-primary-700 dark:border-primary-400 dark:text-primary-500'
: 'border-transparent text-gray-600 hover:border-gray-300 hover:text-gray-700 dark:text-gray-400 dark:hover:border-gray-700 dark:hover:text-gray-100',
'cursor-pointer whitespace-nowrap border-b-2 px-1 py-4 text-sm font-medium'
]"
:aria-current="currentTab === tab.name ? 'page' : undefined"
@click="selectTab(tab.name)"
>{{ tab.label }}</a
>
</nav>
</div>
</div>
</div>
</template>
2 changes: 2 additions & 0 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,12 @@ export { default as NeFormItemLabel } from '@/components/NeFormItemLabel.vue'
export { default as NeRadioSelection } from '@/components/NeRadioSelection.vue'
export { default as NePaginator } from '@/components/NePaginator.vue'
export { default as NeEmptyState } from '@/components/NeEmptyState.vue'
export { default as NeTabs } from '@/components/NeTabs.vue'

// types export
export type { NeComboboxOption } from '@/components/NeCombobox.vue'
export type { NePaginatorProps } from '@/components/NePaginator.vue'
export type { Tab } from '@/components/NeTabs.vue'

// library functions export
export {
Expand Down
27 changes: 25 additions & 2 deletions stories/NeLink.stories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,15 @@ const meta: Meta<typeof NeLink> = {
title: 'Visual/NeLink',
component: NeLink,
tags: ['autodocs'],
args: {}
args: {
invertedTheme: false
}
}
export default meta
type Story = StoryObj<typeof meta>

const template = '<NeLink v-bind="args" class="text-sm">Go to Wikipedia</NeLink>'
const template =
'<NeLink v-bind="args" href="https://www.wikipedia.org/" target="_blank" class="text-sm">Go to Wikipedia</NeLink>'

export const Default: Story = {
render: (args) => ({
Expand All @@ -25,3 +28,23 @@ export const Default: Story = {
}),
args: {}
}

const invertedThemeTemplate = `<div class="text-sm p-4 bg-gray-800 dark:bg-gray-300">
<p class="mb-2 text-gray-300 dark:text-gray-800">
Inverted theme is useful on inverted backgrounds (e.g. inside a tooltip)
</p>
<NeLink v-bind="args" href="https://www.wikipedia.org/" target="_blank">
Go to Wikipedia
</NeLink>
</div>`

export const InvertedTheme: Story = {
render: (args) => ({
components: { NeLink },
setup() {
return { args }
},
template: invertedThemeTemplate
}),
args: { invertedTheme: true }
}
12 changes: 5 additions & 7 deletions stories/NeRadioSelection.stories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ export const Default: StoryObj<typeof NeRadioSelection> = {
return { args }
},
template: `
<NeRadioSelection v-model="args.modelValue" :label="args.label" :options="args.options" />
<NeRadioSelection v-bind="args" />
`
})
}
Expand All @@ -73,8 +73,7 @@ export const WithDescription: StoryObj<typeof NeRadioSelection> = {
return { args }
},
template: `
<NeRadioSelection v-model="args.modelValue" :description="args.description" :label="args.label"
:options="args.options" />
<NeRadioSelection v-bind="args" />
`
}),
args: {
Expand All @@ -89,8 +88,7 @@ export const CardPicker: StoryObj<typeof NeRadioSelection> = {
return { args }
},
template: `
<NeRadioSelection v-model="args.modelValue" :card="args.card" :grid-style="args.gridStyle"
:label="args.label" :options="args.options" />
<NeRadioSelection v-bind="args" />
`
}),
args: {
Expand Down Expand Up @@ -143,7 +141,7 @@ export const Disabled: StoryObj<typeof NeRadioSelection> = {
return { args }
},
template: `
<NeRadioSelection v-model="args.modelValue" :label="args.label" :options="args.options" />
<NeRadioSelection v-bind="args" />
`
}),
args: {
Expand All @@ -158,7 +156,7 @@ export const WithTooltip: StoryObj<typeof NeRadioSelection> = {
return { args }
},
template: `
<NeRadioSelection v-model="args.modelValue" :label="args.label" :options="args.options">\
<NeRadioSelection v-bind="args">\
<template #tooltip>\
<NeTooltip>\
<template #content>Tooltip</template>\
Expand Down
36 changes: 36 additions & 0 deletions stories/NeTabs.stories.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright (C) 2024 Nethesis S.r.l.
// SPDX-License-Identifier: GPL-3.0-or-later

import type { Meta, StoryObj } from '@storybook/vue3'

import { NeTabs } from '../src/main'

const meta = {
title: 'Visual/NeTabs',
component: NeTabs,
argTypes: {},
args: {
tabs: [
{ name: 'firstTab', label: 'First tab' },
{ name: 'secondTab', label: 'Second tab' },
{ name: 'thirdTab', label: 'Third tab' }
],
selected: 'secondTab'
} // default values
} satisfies Meta<typeof NeTabs>

export default meta
type Story = StoryObj<typeof meta>

const template = '<NeTabs v-bind="args" />'

export const Default: Story = {
render: (args) => ({
components: { NeTabs },
setup() {
return { args }
},
template: template
}),
args: {}
}

0 comments on commit fef3cf9

Please sign in to comment.