mirror of
https://github.com/45Drives/cockpit-navigator.git
synced 2025-07-29 16:45:13 +02:00
update components with changes from other plugins
This commit is contained in:
parent
8d498d925b
commit
6b201edc55
@ -1,9 +1,26 @@
|
||||
<!--
|
||||
Copyright (C) 2022 Josh Boudreau <jboudreau@45drives.com>
|
||||
|
||||
This file is part of Cockpit Navigator.
|
||||
|
||||
Cockpit Navigator is free software: you can redistribute it and/or modify it under the terms
|
||||
of the GNU General Public License as published by the Free Software Foundation, either version 3
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
Cockpit Navigator 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with Cockpit Navigator.
|
||||
If not, see <https://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
<template>
|
||||
<SwitchGroup as="div" :class="[labelRight ? 'flex-row-reverse' : 'flex-row', 'inline-flex items-center']">
|
||||
<span :class="[labelRight ? 'grow' : '', 'flex flex-col']">
|
||||
<SwitchLabel as="span" class="text-label" passive><slot /></SwitchLabel>
|
||||
<SwitchLabel as="div" class="text-label"><slot /></SwitchLabel>
|
||||
<SwitchDescription
|
||||
as="span"
|
||||
as="div"
|
||||
class="text-sm text-muted"
|
||||
><slot name="description" /></SwitchDescription>
|
||||
</span>
|
||||
@ -11,11 +28,11 @@
|
||||
<Switch
|
||||
:modelValue="modelValue"
|
||||
@update:modelValue="newValue => { $emit('update:modelValue', newValue); $emit('change', newValue); $emit('input', newValue); }"
|
||||
:class="[modelValue ? 'bg-45d' : 'bg-well', 'relative inline-flex flex-shrink-0 h-6 w-11 p-[2px] rounded-full cursor-pointer focus:outline-none focus:ring-0 shadow-inner']"
|
||||
:class="[modelValue ? 'bg-45d' : 'bg-well', 'inline-flex shrink-0 h-6 w-11 p-[2px] rounded-full cursor-pointer shadow-inner']"
|
||||
>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
:class="[modelValue ? 'translate-x-5' : 'translate-x-0', 'pointer-events-none inline-block h-5 w-5 rounded-full bg-default shadow-md transform ring-0 transition-transform ease-in-out duration-200 top-px']"
|
||||
:class="[modelValue ? 'translate-x-5' : 'translate-x-0', 'pointer-events-none inline-block h-5 w-5 rounded-full bg-default shadow-md transform transition-transform ease-in-out duration-200']"
|
||||
/>
|
||||
</Switch>
|
||||
</SwitchGroup>
|
||||
@ -29,18 +46,6 @@ export default {
|
||||
modelValue: Boolean,
|
||||
labelRight: Boolean,
|
||||
},
|
||||
// setup(props, { emit }) {
|
||||
// const internalModel = ref(props.modelValue);
|
||||
|
||||
// const updateModelValue = () => emit('update:modelValue', internalModel.value);
|
||||
|
||||
// watch(() => props.modelValue, (newValue) => internalModel.value = newValue);
|
||||
|
||||
// return {
|
||||
// internalModel,
|
||||
// updateModelValue,
|
||||
// };
|
||||
// },
|
||||
components: {
|
||||
Switch,
|
||||
SwitchDescription,
|
||||
|
@ -1,37 +1,20 @@
|
||||
<!--
|
||||
Copyright (C) 2022 Josh Boudreau <jboudreau@45drives.com>
|
||||
|
||||
This file is part of Cockpit File Sharing.
|
||||
This file is part of Cockpit Navigator.
|
||||
|
||||
Cockpit File Sharing is free software: you can redistribute it and/or modify it under the terms
|
||||
Cockpit Navigator is free software: you can redistribute it and/or modify it under the terms
|
||||
of the GNU General Public License as published by the Free Software Foundation, either version 3
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
Cockpit File Sharing is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
Cockpit Navigator 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with Cockpit File Sharing.
|
||||
You should have received a copy of the GNU General Public License along with Cockpit Navigator.
|
||||
If not, see <https://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
<template>
|
||||
<div class="aspect-square loading-spinner border-neutral-300 border-t-neutral-500 dark:border-neutral-500 dark:border-t-neutral-200 rounded-full"></div>
|
||||
<div class="aspect-square animate-spin border-neutral-300 border-t-neutral-500 dark:border-neutral-500 dark:border-t-neutral-200 rounded-full"></div>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
.loading-spinner {
|
||||
border-width: 0.2rem;
|
||||
animation: spin 2s linear infinite;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -1,72 +1,63 @@
|
||||
<template>
|
||||
<TransitionRoot as="template" :show="showModal">
|
||||
<Dialog as="div" class="fixed z-10 inset-0 overflow-y-auto">
|
||||
<div
|
||||
class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0 text-default"
|
||||
>
|
||||
<TransitionChild
|
||||
as="template"
|
||||
enter="ease-out duration-300"
|
||||
enter-from="opacity-0"
|
||||
enter-to="opacity-100"
|
||||
leave="ease-in duration-200"
|
||||
leave-from="opacity-100"
|
||||
leave-to="opacity-0"
|
||||
>
|
||||
<DialogOverlay class="fixed inset-0 bg-neutral-500/75 dark:bg-black/50 transition-opacity" />
|
||||
</TransitionChild>
|
||||
<!--
|
||||
Copyright (C) 2022 Josh Boudreau <jboudreau@45drives.com>
|
||||
|
||||
<!-- This element is to trick the browser into centering the modal contents. -->
|
||||
<span class="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true">​</span>
|
||||
<TransitionChild
|
||||
as="template"
|
||||
enter="ease-out duration-300"
|
||||
enter-from="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
||||
enter-to="opacity-100 translate-y-0 sm:scale-100"
|
||||
leave="ease-in duration-200"
|
||||
leave-from="opacity-100 translate-y-0 sm:scale-100"
|
||||
leave-to="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
||||
>
|
||||
<div
|
||||
:class="[autoWidth ? 'sm:max-w-full' : 'sm:max-w-lg', 'relative inline-flex flex-col items-stretch align-bottom overflow-hidden transform transition-all sm:my-8 sm:align-middle text-left card']"
|
||||
>
|
||||
<div class="block w-[512px]"></div>
|
||||
This file is part of Cockpit Navigator.
|
||||
|
||||
Cockpit Navigator is free software: you can redistribute it and/or modify it under the terms
|
||||
of the GNU General Public License as published by the Free Software Foundation, either version 3
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
Cockpit Navigator 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with Cockpit Navigator.
|
||||
If not, see <https://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
<template>
|
||||
<TransitionRoot as="div" class="fixed inset-0 z-10 overflow-visible" :show="showModal">
|
||||
<TransitionChild as="template" enter="ease-out duration-500" enter-from="opacity-0" enter-to="opacity-100"
|
||||
leave="ease-in duration-500" leave-from="opacity-100" leave-to="opacity-0">
|
||||
<div class="fixed z-10 inset-0 bg-neutral-500/75 dark:bg-black/50 transition-opacity" />
|
||||
</TransitionChild>
|
||||
<div class="fixed z-10 inset-0 overflow-hidden flex items-end sm:items-center justify-center px-4 pb-20 sm:p-0">
|
||||
<TransitionChild as="template" enter="ease-out duration-300"
|
||||
enter-from="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-90"
|
||||
enter-to="opacity-100 translate-y-0 sm:scale-100" leave="ease-in duration-100"
|
||||
leave-from="opacity-100 translate-y-0 sm:scale-100"
|
||||
leave-to="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-75">
|
||||
<div
|
||||
:class="[autoWidth ? 'sm:max-w-full' : 'sm:max-w-lg', 'inline-flex flex-col items-stretch overflow-hidden transform transition-all text-left z-10']">
|
||||
<div class="block w-[512px]" /> <!-- set min width of div -->
|
||||
<div class="card flex flex-col items-stretch overflow-hidden">
|
||||
<div class="card-header">
|
||||
<slot name="header">
|
||||
<h3 class="text-header">{{ headerText }}</h3>
|
||||
</slot>
|
||||
</div>
|
||||
<div class="card-body flex flex-row items-center">
|
||||
<div class="shrink-0">
|
||||
<slot name="icon" />
|
||||
</div>
|
||||
<div class="grow">
|
||||
<slot name="icon" />
|
||||
<div class="grow ml-2 only:ml-0 overflow-x-auto">
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer button-group-row w-full justify-end">
|
||||
<button
|
||||
v-if="!noCancel"
|
||||
type="button"
|
||||
class="btn btn-secondary"
|
||||
@click="$emit('cancel')"
|
||||
>{{ cancelText }}</button>
|
||||
<button
|
||||
type="button"
|
||||
:class="['btn', applyDangerous ? 'btn-danger' : 'btn-primary']"
|
||||
@click="$emit('apply')"
|
||||
:disabled="disableContinue"
|
||||
>{{ applyText }}</button>
|
||||
<div class="card-footer button-group-row justify-end">
|
||||
<button v-if="!noCancel" type="button" class="btn btn-secondary" @click="$emit('cancel')">{{
|
||||
cancelText
|
||||
}}</button>
|
||||
<button type="button" :class="['btn', applyDangerous ? 'btn-danger' : 'btn-primary']"
|
||||
@click="$emit('apply')" :disabled="disableContinue">{{ applyText }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</TransitionChild>
|
||||
</div>
|
||||
</Dialog>
|
||||
</div>
|
||||
</TransitionChild>
|
||||
</div>
|
||||
</TransitionRoot>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Dialog, DialogOverlay, DialogTitle, TransitionChild, TransitionRoot } from '@headlessui/vue';
|
||||
import { TransitionChild, TransitionRoot } from '@headlessui/vue';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
@ -92,9 +83,6 @@ export default {
|
||||
disableContinue: Boolean,
|
||||
},
|
||||
components: {
|
||||
Dialog,
|
||||
DialogOverlay,
|
||||
DialogTitle,
|
||||
TransitionChild,
|
||||
TransitionRoot,
|
||||
},
|
||||
|
@ -1,85 +1,70 @@
|
||||
<!--
|
||||
Copyright (C) 2022 Josh Boudreau <jboudreau@45drives.com>
|
||||
|
||||
This file is part of Cockpit Navigator.
|
||||
|
||||
Cockpit Navigator is free software: you can redistribute it and/or modify it under the terms
|
||||
of the GNU General Public License as published by the Free Software Foundation, either version 3
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
Cockpit Navigator 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with Cockpit Navigator.
|
||||
If not, see <https://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
<template>
|
||||
<!-- Global notification live region, render this permanently at the end of the document -->
|
||||
<div
|
||||
aria-live="assertive"
|
||||
class="fixed inset-0 flex items-end px-4 py-6 pointer-events-none sm:p-6 sm:items-start z-20 h-screen overflow-y-auto"
|
||||
>
|
||||
<div class="w-full flex flex-col items-center sm:items-end space-y-content">
|
||||
<!-- Notification panel, dynamically insert this into the live region when it needs to be displayed -->
|
||||
<transition
|
||||
v-for="notification in notificationList"
|
||||
:key="notification.id"
|
||||
enter-active-class="transform ease-out duration-300 transition"
|
||||
enter-from-class="translate-y-2 opacity-0 sm:translate-y-0 sm:translate-x-2"
|
||||
enter-to-class="translate-y-0 opacity-100 sm:translate-x-0"
|
||||
leave-active-class="transition ease-in duration-100"
|
||||
leave-from-class="opacity-100"
|
||||
leave-to-class="opacity-0"
|
||||
class="transition-transform"
|
||||
>
|
||||
<div
|
||||
v-if="notification.show"
|
||||
class="max-w-sm w-full shadow-lg pointer-events-auto overflow-hidden bg-default text-default"
|
||||
@mouseenter="notification.clearTimeouts?.()"
|
||||
@mouseleave="notification.setTimeouts?.()"
|
||||
>
|
||||
<div class="p-4">
|
||||
<div class="flex items-start">
|
||||
<div class="flex-shrink-0" aria-hidden="true">
|
||||
<ExclamationCircleIcon
|
||||
v-if="notification.level === 'error'"
|
||||
class="icon-error size-icon-lg"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<ExclamationCircleIcon
|
||||
v-else-if="notification.level === 'warning'"
|
||||
class="icon-warning size-icon-lg"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<CheckCircleIcon
|
||||
v-else-if="notification.level === 'success'"
|
||||
class="icon-success size-icon-lg"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<MinusCircleIcon
|
||||
v-else-if="notification.level === 'denied'"
|
||||
class="icon-error size-icon-lg"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<InformationCircleIcon v-else class="icon-info size-icon-lg" />
|
||||
</div>
|
||||
<div class="ml-3 w-0 flex-1 pt-0.5">
|
||||
<p class="text-sm font-medium">{{ notification.title }}</p>
|
||||
<p class="mt-1 text-sm text-muted whitespace-pre-wrap" v-html="notification.body"></p>
|
||||
<div v-if="notification.actions?.length" class="mt-3 flex space-x-7">
|
||||
<button
|
||||
v-for="action in notification.actions"
|
||||
@click="action.callback"
|
||||
class="rounded-md text-sm font-medium text-primary focus:outline-none focus:ring-0 focus:ring-offset-0"
|
||||
>
|
||||
{{ action.text }}
|
||||
</button>
|
||||
<button
|
||||
@click="notification.show = false"
|
||||
type="button"
|
||||
class="rounded-md text-sm font-medium text-secondary focus:outline-none focus:ring-0 focus:ring-offset-0"
|
||||
>Dismiss</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ml-4 flex-shrink-0 flex">
|
||||
<button
|
||||
@click="notification.show = false"
|
||||
class="icon-default focus:outline-none focus:ring-0 focus:ring-offset-0"
|
||||
>
|
||||
<span class="sr-only">Close</span>
|
||||
<XIcon class="size-icon" aria-hidden="true" />
|
||||
<div aria-live="assertive"
|
||||
class="fixed inset-0 flex items-end px-4 py-6 pointer-events-none sm:p-6 sm:items-start z-20 h-screen overflow-y-auto">
|
||||
<transition-group tag="div" class="w-full flex flex-col-reverse items-center sm:items-end sm:flex-col space-y-content"
|
||||
enter-active-class="transition-all transform ease-out duration-300"
|
||||
enter-from-class="translate-y-8 opacity-0 scale-95 sm:translate-y-0 sm:translate-x-8"
|
||||
enter-to-class="translate-y-0 opacity-100 scale-100 sm:translate-x-0"
|
||||
leave-active-class="transition-all transform ease-in duration-100"
|
||||
leave-from-class="opacity-100 scale-100 sm:translate-x-0"
|
||||
leave-to-class="opacity-0 scale-95 sm:translate-x-8">
|
||||
<div v-for="notification in notificationList" :key="notification.id"
|
||||
class="max-w-sm w-full shadow-lg pointer-events-auto overflow-hidden bg-default text-default"
|
||||
@mouseenter="notification.clearTimeouts?.()" @mouseleave="notification.setTimeouts?.()">
|
||||
<div class="p-4">
|
||||
<div class="flex items-start">
|
||||
<div class="flex-shrink-0" aria-hidden="true">
|
||||
<ExclamationCircleIcon v-if="notification.level === 'error'" class="icon-error size-icon-lg"
|
||||
aria-hidden="true" />
|
||||
<ExclamationCircleIcon v-else-if="notification.level === 'warning'"
|
||||
class="icon-warning size-icon-lg" aria-hidden="true" />
|
||||
<CheckCircleIcon v-else-if="notification.level === 'success'"
|
||||
class="icon-success size-icon-lg" aria-hidden="true" />
|
||||
<MinusCircleIcon v-else-if="notification.level === 'denied'" class="icon-error size-icon-lg"
|
||||
aria-hidden="true" />
|
||||
<InformationCircleIcon v-else class="icon-info size-icon-lg" />
|
||||
</div>
|
||||
<div class="ml-3 w-0 flex-1 pt-0.5">
|
||||
<p class="text-sm font-medium">{{ notification.title }}</p>
|
||||
<p class="mt-1 text-sm text-muted whitespace-pre-wrap" v-html="notification.body">
|
||||
</p>
|
||||
<div v-if="notification.actions?.length" class="mt-3 flex space-x-7">
|
||||
<button v-for="action in notification.actions" @click="action.callback"
|
||||
class="rounded-md text-sm font-medium text-primary">
|
||||
{{ action.text }}
|
||||
</button>
|
||||
<button @click="notification.show = false" type="button"
|
||||
class="rounded-md text-sm font-medium text-secondary">Dismiss</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ml-4 flex-shrink-0 flex">
|
||||
<button @click="notification.show = false"
|
||||
class="icon-default">
|
||||
<span class="sr-only">Close</span>
|
||||
<XIcon class="size-icon" aria-hidden="true" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
</div>
|
||||
</transition-group>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -87,7 +72,7 @@
|
||||
import { ref, watch, reactive, onUnmounted } from 'vue';
|
||||
import { InformationCircleIcon, ExclamationCircleIcon, MinusCircleIcon, CheckCircleIcon } from '@heroicons/vue/outline';
|
||||
import { XIcon } from '@heroicons/vue/solid';
|
||||
import { FIFO, UniqueIDGenerator } from '@45drives/cockpit-helpers';
|
||||
import { FIFO } from '@45drives/cockpit-helpers';
|
||||
|
||||
/** Notification passed to showNotification
|
||||
*
|
||||
@ -106,13 +91,11 @@ export default {
|
||||
setup(props) {
|
||||
const notificationList = ref([]);
|
||||
|
||||
const uniqueIDGenerator = new UniqueIDGenerator();
|
||||
|
||||
/** Construct new notification and show it
|
||||
*
|
||||
* @param {string} title - Header text
|
||||
* @param {string} body - Notification content
|
||||
* @param {string} [level='info'] - 'info'|'warning'|'error'|'success'
|
||||
* @param {string} [level='info'] - 'info'|'warning'|'error'|'success'|'denied'
|
||||
* @param {number} [timeout=10000] - time to display notification in milliseconds, or zero to display forever
|
||||
*
|
||||
* @returns {Notification} - Object to chain add actions to
|
||||
@ -120,7 +103,6 @@ export default {
|
||||
const constructNotification = (title, body, level = 'info', timeout = 10000) => {
|
||||
const actions = [];
|
||||
const obj = reactive({
|
||||
show: true,
|
||||
title,
|
||||
body,
|
||||
level,
|
||||
@ -137,8 +119,8 @@ export default {
|
||||
obj.actions.push({
|
||||
text,
|
||||
callback: () => {
|
||||
obj.show = false;
|
||||
callback();
|
||||
obj.removeSelf();
|
||||
}
|
||||
});
|
||||
return obj;
|
||||
@ -153,27 +135,27 @@ export default {
|
||||
*/
|
||||
const showNotificationObj = (notificationObj) => {
|
||||
notificationObj.show = true;
|
||||
notificationObj.id = uniqueIDGenerator.get();
|
||||
// backwards compat for setting show to false to remove notification
|
||||
notificationObj.stopShowWatch = watch(() => notificationObj.show, (value) => {
|
||||
if (!value) notificationObj.removeSelf();
|
||||
})
|
||||
notificationObj.id = Math.floor(Math.random() * Date.now());
|
||||
notificationObj.removeSelf = () => {
|
||||
const idToRemove = notificationObj.id
|
||||
notificationList.value = notificationList.value.filter(({ id }) => id !== idToRemove);
|
||||
notificationObj.stopShowWatch();
|
||||
}
|
||||
notificationObj.setTimeouts = () => {
|
||||
if (notificationObj.timeout > 0) {
|
||||
notificationObj.timeout1 = setTimeout(
|
||||
() => notificationObj.show = false,
|
||||
notificationObj.removerTimeout = setTimeout(
|
||||
notificationObj.removeSelf,
|
||||
notificationObj.timeout
|
||||
);
|
||||
notificationObj.timeout2 = setTimeout(
|
||||
() => {
|
||||
notificationList.value = notificationList.value.filter(obj => obj !== notificationObj);
|
||||
uniqueIDGenerator.release(notificationObj.id);
|
||||
},
|
||||
notificationObj.timeout + 2000
|
||||
);
|
||||
}
|
||||
}
|
||||
notificationObj.clearTimeouts = () => {
|
||||
if (notificationObj.timeout1 !== undefined)
|
||||
clearTimeout(notificationObj.timeout1);
|
||||
if (notificationObj.timeout2 !== undefined)
|
||||
clearTimeout(notificationObj.timeout2);
|
||||
if (notificationObj.removerTimeout !== undefined)
|
||||
clearTimeout(notificationObj.removerTimeout);
|
||||
}
|
||||
notificationList.value = [notificationObj, ...notificationList.value];
|
||||
if (notificationObj.level === 'error') {
|
||||
@ -196,12 +178,6 @@ export default {
|
||||
}
|
||||
});
|
||||
|
||||
let cleanupHandle = setInterval(() => {
|
||||
notificationList.value = notificationList.value.filter(n => n.show);
|
||||
}, 1000);
|
||||
|
||||
onUnmounted(() => clearInterval(cleanupHandle));
|
||||
|
||||
return {
|
||||
notificationList,
|
||||
constructNotification,
|
||||
|
@ -1,8 +1,25 @@
|
||||
<!--
|
||||
Copyright (C) 2022 Josh Boudreau <jboudreau@45drives.com>
|
||||
|
||||
This file is part of Cockpit Navigator.
|
||||
|
||||
Cockpit Navigator is free software: you can redistribute it and/or modify it under the terms
|
||||
of the GNU General Public License as published by the Free Software Foundation, either version 3
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
Cockpit Navigator 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with Cockpit Navigator.
|
||||
If not, see <https://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
<template>
|
||||
<div class="shadow border border-default h-full">
|
||||
<div class="shadow border border-default h-full overflow-hidden">
|
||||
<div
|
||||
v-if="!noHeader"
|
||||
class="bg-accent py-3 px-4 lg:pl-8 lg:pr-6 text-sm font-semibold flex flex-row"
|
||||
class="bg-accent py-3 px-4 lg:px-6 text-sm font-semibold flex flex-row"
|
||||
>
|
||||
<div class="grow">
|
||||
<slot name="header">{{ headerText }}</slot>
|
||||
@ -80,7 +97,7 @@ table.houston-table thead.use-sticky tr th {
|
||||
|
||||
table.houston-table th,
|
||||
table.houston-table td {
|
||||
@apply py-2 px-4 lg:pl-8 lg:pr-6 whitespace-nowrap text-sm;
|
||||
@apply py-2 px-4 lg:px-6 whitespace-nowrap text-sm;
|
||||
}
|
||||
|
||||
table.houston-table th:not(.text-right):not(.text-center),
|
||||
|
@ -1,101 +0,0 @@
|
||||
<template>
|
||||
<div class="flex flex-col h-full">
|
||||
<div class="inline-block w-full align-middle h-full">
|
||||
<div class="shadow md:rounded-[9px] border border-default h-full">
|
||||
<div
|
||||
v-if="!noHeader"
|
||||
class="md:rounded-t-[8px] bg-accent py-3 px-4 lg:pl-8 lg:pr-6 text-sm font-semibold flex flex-row"
|
||||
>
|
||||
<div class="grow">
|
||||
<slot name="header">
|
||||
{{ headerText }}
|
||||
</slot>
|
||||
</div>
|
||||
<div :class="[noScroll ? '' : 'overflow-y-auto']" :style="{'scrollbar-gutter': noScroll ? 'auto' : 'stable'}"></div>
|
||||
</div>
|
||||
<div
|
||||
:class="[noShrink ? noShrinkHeight : shrinkHeight, noScroll ? '' : 'overflow-y-scroll', noHeader ? 'md:rounded-t-[8px]' : '', 'flex flex-col md:rounded-b-[8px] overflow-x-auto']"
|
||||
:style="{'scrollbar-gutter': noScroll ? 'auto' : 'stable'}"
|
||||
>
|
||||
<table class="min-w-full divide houston-table">
|
||||
<thead :class="[stickyHeaders ? 'use-sticky' : '']">
|
||||
<slot name="thead" />
|
||||
</thead>
|
||||
<tbody class="bg-default w-full">
|
||||
<slot name="tbody">
|
||||
<tr>
|
||||
<td colspan="100%" class="text-center align-middle text-muted text-sm">{{ emptyText }}</td>
|
||||
</tr>
|
||||
</slot>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
headerText: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: "Table",
|
||||
},
|
||||
emptyText: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: "Nothing to show.",
|
||||
},
|
||||
noShrink: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
stickyHeaders: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
noShrinkHeight: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: 'h-80'
|
||||
},
|
||||
shrinkHeight: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: 'max-h-80'
|
||||
},
|
||||
noScroll: Boolean,
|
||||
noHeader: Boolean,
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
@import '@45drives/cockpit-css/src/index.css';
|
||||
|
||||
table.houston-table thead.use-sticky tr th {
|
||||
@apply sticky z-10 top-0;
|
||||
}
|
||||
|
||||
table.houston-table th,
|
||||
table.houston-table td {
|
||||
@apply py-2 px-4 lg:pl-8 lg:pr-6 whitespace-nowrap text-sm;
|
||||
}
|
||||
|
||||
table.houston-table th:not(.text-right):not(.text-center),
|
||||
table.houston-table td:not(.text-right):not(.text-center) {
|
||||
@apply text-left;
|
||||
}
|
||||
|
||||
table.houston-table th {
|
||||
@apply bg-accent font-semibold;
|
||||
}
|
||||
|
||||
table.houston-table tr {
|
||||
@apply even:bg-accent;
|
||||
}
|
||||
</style>
|
Loading…
x
Reference in New Issue
Block a user