Skip to content

Commit

Permalink
Create button component
Browse files Browse the repository at this point in the history
Signed-off-by: Marco Ambrosini <marcoambrosini@pm.me>
  • Loading branch information
marcoambrosini committed Aug 6, 2021
1 parent 796fd99 commit 8b54c05
Show file tree
Hide file tree
Showing 6 changed files with 330 additions and 1 deletion.
8 changes: 8 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
"vue-color": "^2.7.1",
"vue-material-design-icons": "^4.11.0",
"vue-multiselect": "^2.1.6",
"vue-ripple-directive": "^2.0.1",
"vue-visible": "^1.0.2",
"vue2-datepicker": "^3.6.3"
},
Expand Down
2 changes: 1 addition & 1 deletion src/assets/inputs.scss
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
*/

/* Default global values */
button,
button:not(.button-vue),
input:not([type='range']),
textarea {
margin: 0;
Expand Down
293 changes: 293 additions & 0 deletions src/components/Button/Button.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,293 @@
<!--
- @copyright Copyright (c) 2020 Marco Ambrosini <marcoambrosini@pm.me>
-
- @author Marco Ambrosini <marcoambrosini@pm.me>
-
- @license GNU AGPL version 3 or any later version
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as
- published by the Free Software Foundation, either version 3 of the
- License, or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-->

<docs>

### General description
```
<Button
text="Example text" />
<Button
text="Example text"
color="primary" />
<Button
text="Example text"
color="success" />
<Button
text="Example text"
color="error" />
<Button
text="Example text"
color="warning" />
```
### Usage

</docs>

<template>
<button
class="button-vue"
v-bind="$attrs"
:class="buttonClassObject"
@click="handleClick"
@blur="handleBlur"
@keyup.tab.exact="handleTabUp">
<span class="button-vue__wrapper">
<span v-if="hasIcon" class="button-vue__icon">
<slot />
</span>
<span v-if="hasText" class="button-vue__text">{{ text }}</span>
</span>
</button>
</template>
<script>
// import Ripple from 'vue-ripple-directive'
export default {
name: 'Button',
// directives: {
// Ripple,
// },
props: {
/**
* The text of the button
*/
text: {
type: String,
default: '',
},
/**
* Specifies the button color
* Accepted values: primary, error, warning, success. If left empty,
* the default button style will be used.
*/
color: {
type: String,
validator(value) {
return ['primary', 'error', 'warning', 'success', ''].indexOf(value) !== -1
},
default: '',
},
/**
* Specifies whether the button should span all the available width.
* By default, buttons span the whole width of the container.
*/
wide: {
type: Boolean,
default: true,
},
},
data() {
return {
/**
* Keeps track of whether the element's focus status is due to having
* tabbed to it. We use this to display a thick 'focus outline' only
* when the user is navigating with the keyboard.
*/
tabbed: false,
}
},
computed: {
hasText() {
return this.text
},
hasIcon() {
return this.$slots.default !== undefined
},
iconOnly() {
return this.hasIcon && !this.hasText
},
textOnly() {
return !this.hasIcon && this.hasText
},
iconAndText() {
return this.hasIcon && this.hasText
},
// Classes applied to the button element
buttonClassObject() {
return {
// If icon only, some additional css rules are required
'button-vue--icon-only': this.iconOnly,
'button-vue--text-only': this.textOnly,
'button-vue--icon-and-text': this.iconAndText,
'vue-default': !this.color,
[`vue-${this.color}`]: this.color,
wide: this.wide,
tabbed: this.tabbed,
}
},
},
methods: {
// Forward the click event to the parent component
handleClick(event) {
this.$emit('click', event)
},
// When the tab key is lifted, the button has been "tabbed in"
handleTabUp() {
this.tabbed = true
},
// Everytime the button is blurred, we remove the tabbed state
handleBlur() {
this.tabbed = false
},
},
}
</script>

<style lang="scss" scoped>
.button-vue {
position: relative;
overflow: hidden;
border: 0;
font-size: var(--default-font-size);
font-weight: bold;
height: $clickable-area;
min-width: $clickable-area;
display: flex;
align-items: center;
justify-content: center;
border-radius: var(--border-radius-pill);
transition: background-color 0.1s linear !important;
transition: border 0.1s linear;
// No outline feedback for focus. Handled with a toggled class in js (see data)
&:focus {
outline: none;
}
// No active state for buttons
&:active {
background-color: unset;
}
&__wrapper {
display: inline-flex;
align-items: center;
justify-content: space-around;
}
&__icon {
height: 44px;
width: 44px;
display: flex;
justify-content: center;
align-items: center;
}
&__text {
font-weight: bold;
}
// Icon-only button
&--icon-only {
width: $clickable-area !important;
}
// Text-only button
&--text-only {
padding: 0 12px;
}
// Icon and text button
&--icon-and-text {
padding: 0 16px 0 4px;
}
// Wide button spans the whole width of the container
&.wide {
width: 100%;
}
// We use around our buttons instead of an outline, so that the added "border"
// coincides with the border of the element.
&.tabbed {
box-shadow: 0px 0px 0px 2px var(--color-main-text);
}
}
// Button colors
// Default
.vue-default{
background-color: var(--color-primary-light);
color: var(--color-primary);
&:hover,
&:focus {
background-color: var(--color-primary-light-hover);
}
}
// Primary
.vue-primary {
background-color: var(--color-primary);
color: var(--color-primary-text);
&:hover,
&:focus {
background-color: var(--color-primary-hover);
}
}
// Success
.vue-success {
background-color: var(--color-success);
color: var(--color-primary-text);
&:hover,
&:focus {
background-color: var(--color-success-hover);
}
}
// Warning
.vue-warning {
background-color: var(--color-warning);
color: var(--color-primary-text);
&:hover,
&:focus {
background-color: var(--color-warning-hover);
}
}
// Error
.vue-error {
background-color: var(--color-error);
color: var(--color-primary-text);
&:hover,
&:focus {
background-color: var(--color-error-hover);
}
}
</style>
25 changes: 25 additions & 0 deletions src/components/Button/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/**
* @copyright Copyright (c) 2020 Marco Ambrosini <marcoambrosini@pm.me>
*
* @author Marco Ambrosini <marcoambrosini@pm.me>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

import Button from './Button'

export default Button
2 changes: 2 additions & 0 deletions src/components/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ import PopoverMenu from './PopoverMenu'
import RichContenteditable from './RichContenteditable'
import SettingsSection from './SettingsSection'
import UserBubble from './UserBubble'
import Button from './Button'

export {
ActionButton,
Expand Down Expand Up @@ -115,4 +116,5 @@ export {
SettingsSection,
UserBubble,
ActionCaption,
Button,
}

0 comments on commit 8b54c05

Please sign in to comment.