mirror of
https://github.com/YunoHost/yunohost-admin.git
synced 2024-09-03 20:06:15 +02:00
Add RecursiveListGroup component that display trees
This commit is contained in:
parent
b0077f815d
commit
dd35c097c8
3 changed files with 121 additions and 0 deletions
112
app/src/components/RecursiveListGroup.vue
Normal file
112
app/src/components/RecursiveListGroup.vue
Normal file
|
@ -0,0 +1,112 @@
|
|||
<template>
|
||||
<b-list-group :flush="flush" :style="{ '--depth': tree.depth }">
|
||||
<template v-for="(node, i) in tree.children">
|
||||
<b-list-group-item
|
||||
:key="node.id"
|
||||
class="list-group-item-action" :class="getClasses(node, i)"
|
||||
@click="$router.push(node.data.to)"
|
||||
>
|
||||
<slot name="default" v-bind="node" />
|
||||
|
||||
<b-button
|
||||
v-if="node.children"
|
||||
size="xs" variant="outline-secondary"
|
||||
:aria-expanded="node.data.opened ? 'true' : 'false'" :aria-controls="'collapse-' + node.id"
|
||||
:class="node.data.opened ? 'not-collapsed' : 'collapsed'" class="ml-2"
|
||||
@click.stop="node.data.opened = !node.data.opened"
|
||||
>
|
||||
<span class="sr-only">{{ toggleText }}</span>
|
||||
<icon iname="chevron-right" />
|
||||
</b-button>
|
||||
</b-list-group-item>
|
||||
|
||||
<b-collapse
|
||||
v-if="node.children" :key="'collapse-' + node.id"
|
||||
v-model="node.data.opened" :id="'collapse-' + node.id"
|
||||
>
|
||||
<recursive-list-group
|
||||
:tree="node"
|
||||
:last="last !== undefined ? last : i === tree.children.length - 1" flush
|
||||
>
|
||||
<!-- PASS THE DEFAULT SLOT WITH SCOPE TO NEXT NESTED COMPONENT -->
|
||||
<template slot="default" slot-scope="scope">
|
||||
<slot name="default" v-bind="scope" />
|
||||
</template>
|
||||
</recursive-list-group>
|
||||
</b-collapse>
|
||||
</template>
|
||||
</b-list-group>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'RecursiveListGroup',
|
||||
|
||||
props: {
|
||||
tree: { type: Object, required: true },
|
||||
flush: { type: Boolean, default: false },
|
||||
last: { type: Boolean, default: undefined },
|
||||
toggleText: { type: String, default: null }
|
||||
},
|
||||
|
||||
methods: {
|
||||
getClasses (node, i) {
|
||||
const children = node.height > 0
|
||||
const opened = children && node.data.opened
|
||||
const last = this.last !== false && (!children || !opened) && i === this.tree.children.length - 1
|
||||
return { collapsible: children, uncollapsible: !children, opened, last }
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.list-group {
|
||||
.collapse {
|
||||
&:not(.show) + .list-group-item {
|
||||
border-end-start-radius: $border-radius;
|
||||
}
|
||||
&.show + .list-group-item {
|
||||
border-start-start-radius: $border-radius;
|
||||
}
|
||||
|
||||
+ .list-group-item {
|
||||
border-block-start-width: 1px !important;
|
||||
}
|
||||
}
|
||||
|
||||
&-item {
|
||||
&-action {
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: unset;
|
||||
}
|
||||
|
||||
&.collapsible.opened {
|
||||
border-end-start-radius: $border-radius;
|
||||
}
|
||||
&.collapsible:not(.opened, .last) {
|
||||
border-block-end-width: 0;
|
||||
}
|
||||
|
||||
&.last {
|
||||
border-block-end-width: $list-group-border-width;
|
||||
border-end-start-radius: $border-radius;
|
||||
}
|
||||
}
|
||||
|
||||
&-flush .list-group-item {
|
||||
margin-inline-start: calc(1rem * var(--depth));
|
||||
border-inline-end: $list-group-border-width solid $list-group-border-color;
|
||||
border-inline-start: $list-group-border-width solid $list-group-border-color;
|
||||
text-decoration: none;
|
||||
background-color: $list-group-hover-bg;
|
||||
|
||||
@include hover-focus() {
|
||||
background-color: darken($list-group-hover-bg, 3%);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -97,3 +97,7 @@ $fa-font-size-base: $font-size-base;
|
|||
// ╰────────────────────╯
|
||||
|
||||
$thin-border: $hr-border-width solid $hr-border-color;
|
||||
|
||||
$btn-padding-y-xs: .25rem;
|
||||
$btn-padding-x-xs: .35rem;
|
||||
$btn-line-height-xs: 1.5;
|
||||
|
|
|
@ -58,6 +58,11 @@ body {
|
|||
}
|
||||
}
|
||||
|
||||
// Add xs sized btn
|
||||
.btn-xs {
|
||||
@include button-size($btn-padding-y-xs, $btn-padding-x-xs, $btn-font-size-sm, $btn-line-height-xs, $btn-border-radius-sm);
|
||||
}
|
||||
|
||||
// Allow state of input group to be displayed under the group
|
||||
.input-group .is-invalid ~ .invalid-feedback {
|
||||
display: block;
|
||||
|
|
Loading…
Reference in a new issue