mirror of
https://github.com/YunoHost/yunohost-admin.git
synced 2024-09-03 20:06:15 +02:00
Add Card component helper and update CardForm to use it
This commit is contained in:
parent
9e747579e1
commit
694bdb6ea1
4 changed files with 126 additions and 42 deletions
92
app/src/components/globals/Card.vue
Normal file
92
app/src/components/globals/Card.vue
Normal file
|
@ -0,0 +1,92 @@
|
|||
<template>
|
||||
<b-card v-bind="$attrs" :no-body="collapsable ? true : $attrs['no-body']">
|
||||
<template #header>
|
||||
<div class="w-100 d-flex align-items-center flex-wrap custom-header">
|
||||
<slot name="header">
|
||||
<component :is="titleTag" class="custom-header-title">
|
||||
<icon v-if="icon" :iname="icon" class="mr-2" />{{ title }}
|
||||
</component>
|
||||
</slot>
|
||||
|
||||
<div v-if="hasButtons" class="mt-2 w-100 custom-header-buttons" :class="{ [`ml-${buttonUnbreak}-auto mt-${buttonUnbreak}-0 w-${buttonUnbreak}-auto`]: buttonUnbreak }">
|
||||
<slot name="header-buttons" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<b-button
|
||||
v-if="collapsable" @click="visible = !visible"
|
||||
size="sm" variant="outline-secondary"
|
||||
class="align-self-center ml-auto" :class="{ 'not-collapsed': visible, 'collapsed': !visible, [`ml-${buttonUnbreak}-2`]: buttonUnbreak }"
|
||||
>
|
||||
<icon iname="chevron-right" />
|
||||
<span class="sr-only">{{ $t('words.collapse') }}</span>
|
||||
</b-button>
|
||||
</template>
|
||||
|
||||
<b-collapse v-if="collapsable" :visible="visible">
|
||||
<slot v-if="('no-body' in $attrs)" name="default" />
|
||||
<b-card-body v-else>
|
||||
<slot name="default" />
|
||||
</b-card-body>
|
||||
</b-collapse>
|
||||
<slot v-else name="default" slot="default" />
|
||||
|
||||
<slot name="footer" slot="footer">
|
||||
<slot name="buttons" />
|
||||
</slot>
|
||||
</b-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
name: 'Card',
|
||||
|
||||
props: {
|
||||
id: { type: String, default: 'ynh-form' },
|
||||
title: { type: String, default: null },
|
||||
titleTag: { type: String, default: 'h2' },
|
||||
icon: { type: String, default: null },
|
||||
collapsable: { type: Boolean, default: false },
|
||||
collapsed: { type: Boolean, default: false },
|
||||
buttonUnbreak: { type: String, default: 'md' }
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
visible: !this.collapsed
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
hasButtons () {
|
||||
return 'header-buttons' in this.$slots
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.card-header {
|
||||
display: flex;
|
||||
|
||||
.custom-header {
|
||||
& > :first-child {
|
||||
margin-right: 1rem;
|
||||
}
|
||||
|
||||
.btn + .btn {
|
||||
margin-left: .5rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.card-footer {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
|
||||
& > *:not(:first-child) {
|
||||
margin-left: .5rem;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,30 +1,29 @@
|
|||
<template>
|
||||
<b-card class="card-form">
|
||||
<template v-slot:header>
|
||||
<component :is="titleTag"><icon v-if="icon" :iname="icon" /> {{ title }}</component>
|
||||
<card v-bind="$attrs" class="card-form">
|
||||
<template #default>
|
||||
<slot name="disclaimer" />
|
||||
|
||||
<b-form
|
||||
:id="id" :inline="inline" :class="formClasses"
|
||||
@submit.prevent="onSubmit" novalidate
|
||||
>
|
||||
<slot name="default" />
|
||||
|
||||
<slot name="server-error">
|
||||
<b-alert variant="danger" :show="serverError !== ''" v-html="serverError" />
|
||||
</slot>
|
||||
</b-form>
|
||||
</template>
|
||||
|
||||
<slot name="disclaimer" />
|
||||
|
||||
<b-form :id="id" @submit.prevent="onSubmit" novalidate>
|
||||
<slot name="default" />
|
||||
|
||||
<slot name="server-error">
|
||||
<b-alert variant="danger" :show="serverError !== ''" v-html="serverError" />
|
||||
</slot>
|
||||
</b-form>
|
||||
|
||||
<template v-if="!noFooter" v-slot:footer>
|
||||
<slot name="buttons">
|
||||
<b-button
|
||||
type="submit" variant="success"
|
||||
:form="id" :disabled="disabled"
|
||||
>
|
||||
{{ submitText ? submitText : $t('save') }}
|
||||
</b-button>
|
||||
</slot>
|
||||
</template>
|
||||
</b-card>
|
||||
<slot name="buttons" slot="buttons">
|
||||
<b-button
|
||||
type="submit" variant="success"
|
||||
:form="id" :disabled="disabled"
|
||||
>
|
||||
{{ submitText ? submitText : $t('save') }}
|
||||
</b-button>
|
||||
</slot>
|
||||
</card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
@ -34,13 +33,11 @@ export default {
|
|||
|
||||
props: {
|
||||
id: { type: String, default: 'ynh-form' },
|
||||
title: { type: String, required: true },
|
||||
titleTag: { type: String, default: 'h2' },
|
||||
icon: { type: String, default: null },
|
||||
submitText: { type: String, default: null },
|
||||
noFooter: { type: Boolean, default: false },
|
||||
validation: { type: Object, default: null },
|
||||
serverError: { type: String, default: '' }
|
||||
serverError: { type: String, default: '' },
|
||||
inline: { type: Boolean, default: false },
|
||||
formClasses: { type: [Array, String, Object], default: null }
|
||||
},
|
||||
|
||||
computed: {
|
||||
|
@ -63,12 +60,4 @@ export default {
|
|||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.card-form .card-footer {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
|
||||
& > *:not(:first-child) {
|
||||
margin-left: .5rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -35,7 +35,10 @@
|
|||
</b-link>
|
||||
</div>
|
||||
|
||||
<div v-if="description" v-html="description" :class="{ ['alert p-1 px-2 alert-' + descriptionVariant]: descriptionVariant }"/>
|
||||
<div
|
||||
v-if="description" v-html="description"
|
||||
:class="{ ['alert p-1 px-2 alert-' + descriptionVariant]: descriptionVariant }"
|
||||
/>
|
||||
</template>
|
||||
<!-- Slot available to overwrite the one above -->
|
||||
<slot name="description" />
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<b-button-toolbar :aria-label="label" id="view-top-bar">
|
||||
<b-button-toolbar :aria-label="label" id="top-bar">
|
||||
<div id="top-bar-left" class="top-bar-group" v-if="hasLeftSlot">
|
||||
<slot name="group-left" />
|
||||
</div>
|
||||
|
@ -16,7 +16,7 @@
|
|||
|
||||
<script>
|
||||
export default {
|
||||
name: 'ViewTopBar',
|
||||
name: 'TopBar',
|
||||
|
||||
props: {
|
||||
label: { type: String, default: null },
|
||||
|
@ -24,7 +24,7 @@ export default {
|
|||
type: Object,
|
||||
default: null,
|
||||
validator (value) {
|
||||
return ['text', 'to'].forEach(prop => (prop in value))
|
||||
return ['text', 'to'].every(prop => (prop in value))
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -46,7 +46,7 @@ export default {
|
|||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
#view-top-bar {
|
||||
#top-bar {
|
||||
margin-bottom: 2rem;
|
||||
flex-wrap: wrap-reverse;
|
||||
|
||||
|
|
Loading…
Reference in a new issue