Skip to content

Commit

Permalink
feat: icon only buttons (#4642)
Browse files Browse the repository at this point in the history
feat: icon only buttons

- button can be set as icon only using a prop
- the btn label is used as default tooltip
- additional tooltip can be set with tooltip property
  • Loading branch information
connoratrug authored Jan 30, 2025
1 parent 6bf27b1 commit b4a61dc
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 5 deletions.
23 changes: 18 additions & 5 deletions apps/tailwind-components/components/Button.vue
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,25 @@ const props = withDefaults(
icon?: string;
iconPosition?: ButtonIconPosition;
disabled?: boolean;
iconOnly?: boolean;
tooltip?: string;
}>(),
{
type: "primary",
size: "medium",
label: "",
iconPosition: "left",
disabled: false,
iconOnly: false,
}
);
watchEffect(() => {
if (props.iconOnly && (props.label === "" || props.label === undefined)) {
console.error("Icon only buttons must have a label");
}
});
const COLOR_MAPPING = {
primary:
"tracking-widest uppercase font-display bg-button-primary text-button-primary border-button-primary hover:bg-button-primary-hover hover:text-button-primary-hover hover:border-button-primary-hover",
Expand Down Expand Up @@ -55,22 +64,26 @@ const colorClasses = computed(() => {
});
const sizeClasses = computed(() => {
return SIZE_MAPPING[props.size];
return props.iconOnly ? "p-[8px]" : SIZE_MAPPING[props.size];
});
const iconPositionClass = computed(() => {
return ICON_POSITION_MAPPING[props.iconPosition];
});
const tooltipText = computed(() => {
return props.tooltip || props.iconOnly ? props.label : "";
});
</script>

<template>
<button
v-tooltip.bottom="tooltipText"
class="flex items-center border rounded-input group-[.button-bar]:rounded-none group-[.button-bar]:first:rounded-l-input group-[.button-bar]:last:rounded-r-input"
:class="`${colorClasses} ${sizeClasses} ${iconPositionClass} transition-colors`"
>
<span v-if="icon">
<BaseIcon :name="icon" />
</span>
<span>{{ label }}<slot /></span>
<BaseIcon v-if="icon" :name="icon" />

<span :class="{ 'sr-only': iconOnly }">{{ label }}<slot /></span>
</button>
</template>
49 changes: 49 additions & 0 deletions apps/tailwind-components/pages/Button.story.vue
Original file line number Diff line number Diff line change
Expand Up @@ -60,5 +60,54 @@
CaretDown
</Button>
</div>

<h2 class="text-2xl text-title">Icon only</h2>
<div class="flex flex-col gap-4">
<div class="flex gap-4">
<Button iconOnly icon="plus" label="add" />
<Button iconOnly icon="plus" label="add" type="secondary" />
<Button iconOnly icon="plus" label="add" type="tertiary" />
<Button iconOnly icon="plus" label="add" type="outline" />
<Button iconOnly icon="plus" label="add" type="disabled" />
<Button iconOnly icon="plus" label="add" type="filterWell" />
</div>

<div class="flex gap-4">
<Button iconOnly icon="trash" label="Remove" />
<Button iconOnly icon="trash" label="Remove" type="secondary" />
<Button iconOnly icon="trash" label="Remove" type="tertiary" />
<Button iconOnly icon="trash" label="Remove" type="outline" />
<Button iconOnly icon="trash" label="Remove" type="disabled" />
<Button iconOnly icon="trash" label="Remove" type="filterWell" />
</div>

<div class="flex gap-4">
<Button iconOnly icon="caret-up" label="previous" />
<Button iconOnly icon="caret-up" label="previous" type="secondary" />
<Button iconOnly icon="caret-up" label="previous" type="tertiary" />
<Button iconOnly icon="caret-up" label="previous" type="outline" />
<Button iconOnly icon="caret-up" label="previous" type="disabled" />
<Button iconOnly icon="caret-up" label="previous" type="filterWell" />
</div>

<div class="flex gap-4">
<Button iconOnly icon="caret-down" label="next" />
<Button iconOnly icon="caret-down" label="next" type="secondary" />
<Button iconOnly icon="caret-down" label="next" type="tertiary" />
<Button iconOnly icon="caret-down" label="next" type="outline" />
<Button iconOnly icon="caret-down" label="next" type="disabled" />
<Button iconOnly icon="caret-down" label="next" type="filterWell" />
</div>

<!-- do not render by default to avoid errors on clean load-->
<div v-if="route.query.showError" class="flex gap-4">
<!-- this should result in an error ( due to missing label)-->
<Button iconOnly icon="plus"></Button>
</div>
</div>
</div>
</template>

<script setup lang="ts">
const route = useRoute();
</script>
5 changes: 5 additions & 0 deletions apps/tailwind-components/pages/ButtonBar.story.vue
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,9 @@
<Button icon="caret-down" size="small">three</Button>
<Button icon="trash" size="small">four</Button>
</ButtonBar>

<ButtonBar class="mt-4">
<Button :icon-only="true" icon="caret-up" label="up up up !" />
<Button :icon-only="true" icon="caret-down" label="going down" />
</ButtonBar>
</template>

0 comments on commit b4a61dc

Please sign in to comment.