Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Always show action buttons #420

Merged
merged 12 commits into from
Aug 30, 2024
Merged
4 changes: 2 additions & 2 deletions docs/stacks/vue/coalesce-vue-vuetify/components/c-table.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,9 @@ If provided, specifies which properties, and their ordering, should be given a c

If not provided, all non-key columns that aren't annotated with [[Hidden(HiddenAttribute.Areas.List)]](/modeling/model-components/attributes/hidden.md) are given a column.

<Prop def="extraHeaders?: string[]" lang="ts" />
<Prop def="extraHeaders?: string[] | {header: string; isFixed: boolean }[]" lang="ts" />

The text contents of one or more extra ``th`` elements to render in the table. Should be used in conjunction with the ``item.append`` slot.
The text contents of one or more extra ``th`` elements to render in the table. Each header can be defined as either fixed (sticky) or scrollable. Should be used in conjunction with the ``item.append`` slot.

<Prop def="editable: boolean = false" lang="ts" />

Expand Down
12 changes: 9 additions & 3 deletions src/coalesce-vue-vuetify3/src/components/admin/c-admin-table.vue
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@
:editable="editable"
:list="viewModel"
:extra-headers="
canEdit || canDelete || hasInstanceMethods ? ['Actions'] : []
canEdit || canDelete || hasInstanceMethods
? [{ header: 'Actions', isFixed: true }]
: []
"
:loaders="{
'': list.$modelOnlyMode
Expand All @@ -32,8 +34,12 @@
],
}"
>
<template #item-append="{ item }">
<td width="1%" class="c-admin-table--actions">
<template #item-append="{ item, isHorizontalScrollbarVisible }">
<td
width="1%"
:class="{ ['fixed-column-right']: isHorizontalScrollbarVisible }"
class="c-admin-table--actions"
>
<div class="d-flex flex-nowrap text-no-wrap ga-1" no-gutters>
<v-btn
v-if="editable && !effectiveAutoSave"
Expand Down
92 changes: 82 additions & 10 deletions src/coalesce-vue-vuetify3/src/components/display/c-table.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<template>
<div class="c-table" :class="{ 'c-table--editable': editable }">
<div ref="cTable" class="c-table" :class="{ 'c-table--editable': editable }">
<c-loader-status
:loaders="{ 'no-initial-content': [list.$load], ...loaders }"
>
Expand All @@ -11,6 +11,8 @@
:key="'header-' + header.value"
class="text-left"
:class="{
['fixed-column-right']:
header.isFixed && isHorizontalScrollbarVisible,
sortable: header.sortable,
['prop-' + header.prop]: !!header.prop,
['th-' + header.value]: !header.prop,
Expand Down Expand Up @@ -64,7 +66,11 @@
<c-admin-display v-else-if="admin" :model="item" :for="prop" />
<c-display v-else :model="item" :for="prop" />
</td>
<slot name="item-append" :item="item" />
<slot
name="item-append"
:item="item"
:isHorizontalScrollbarVisible="isHorizontalScrollbarVisible"
/>
</tr>
</tbody>
</v-table>
Expand All @@ -73,7 +79,13 @@
</template>

<script lang="ts">
import { defineComponent, PropType } from "vue";
import {
defineComponent,
onMounted,
onUnmounted,
PropType,
ref,
} from "vue";
import {
ListViewModel,
Property,
Expand All @@ -92,10 +104,49 @@ export default defineComponent({
props: { required: false, type: Array as PropType<Array<string>> },
admin: { required: false, type: Boolean },
editable: { required: false, type: Boolean },
extraHeaders: { required: false, type: Array as PropType<Array<string>> },
extraHeaders: {
required: false,
type: Array as
| PropType<Array<{ header: string; isFixed: boolean }>>
| PropType<Array<string>>,
},
loaders: { required: false, type: Object },
},

setup() {
meghanmae marked this conversation as resolved.
Show resolved Hide resolved
const cTable = ref<HTMLDivElement>();
const isHorizontalScrollbarVisible = ref(false);

const checkHorizontalScrollbar = () => {
const divElement = cTable.value;
const tableElement = divElement?.querySelector("table");
if (tableElement && divElement) {
isHorizontalScrollbarVisible.value =
divElement.clientWidth < tableElement.clientWidth;
}
};

const resizeObserver = new ResizeObserver(() => {
checkHorizontalScrollbar();
});

onMounted(() => {
if (cTable.value) {
resizeObserver.observe(cTable.value);
}
checkHorizontalScrollbar();
});

onUnmounted(() => {
resizeObserver.disconnect();
});

return {
cTable,
isHorizontalScrollbarVisible,
};
},

computed: {
metadata(): ModelType {
return this.list.$metadata;
Expand All @@ -121,13 +172,27 @@ export default defineComponent({
sortable: o.type != "collection",
align: "left",
prop: o.name,
isFixed: false,
})),
...(this.extraHeaders || []).map((h) => ({
text: h,
value: h,
sortable: false,
prop: undefined,
})),
...(this.extraHeaders || []).map((h) => {
if (typeof h === "string") {
return {
text: h,
value: h,
sortable: false,
prop: undefined,
isFixed: false,
};
} else {
return {
text: h.header,
value: h.header,
sortable: false,
prop: undefined,
isFixed: h.isFixed,
};
}
}),
];
},
},
Expand Down Expand Up @@ -207,5 +272,12 @@ export default defineComponent({
font-size: 16px;
}
}

.fixed-column-right {
position: sticky;
right: 0;
background: rgb(var(--v-theme-surface-light));
box-shadow: -2px 2px 4px 0px rgba(0, 0, 0, 0.4);
}
}
</style>
Loading