mirror of
https://github.com/45Drives/cockpit-navigator.git
synced 2025-07-31 01:24:37 +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>
|
<template>
|
||||||
<SwitchGroup as="div" :class="[labelRight ? 'flex-row-reverse' : 'flex-row', 'inline-flex items-center']">
|
<SwitchGroup as="div" :class="[labelRight ? 'flex-row-reverse' : 'flex-row', 'inline-flex items-center']">
|
||||||
<span :class="[labelRight ? 'grow' : '', 'flex flex-col']">
|
<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
|
<SwitchDescription
|
||||||
as="span"
|
as="div"
|
||||||
class="text-sm text-muted"
|
class="text-sm text-muted"
|
||||||
><slot name="description" /></SwitchDescription>
|
><slot name="description" /></SwitchDescription>
|
||||||
</span>
|
</span>
|
||||||
@ -11,11 +28,11 @@
|
|||||||
<Switch
|
<Switch
|
||||||
:modelValue="modelValue"
|
:modelValue="modelValue"
|
||||||
@update:modelValue="newValue => { $emit('update:modelValue', newValue); $emit('change', newValue); $emit('input', newValue); }"
|
@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
|
<span
|
||||||
aria-hidden="true"
|
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>
|
</Switch>
|
||||||
</SwitchGroup>
|
</SwitchGroup>
|
||||||
@ -29,18 +46,6 @@ export default {
|
|||||||
modelValue: Boolean,
|
modelValue: Boolean,
|
||||||
labelRight: 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: {
|
components: {
|
||||||
Switch,
|
Switch,
|
||||||
SwitchDescription,
|
SwitchDescription,
|
||||||
|
@ -1,37 +1,20 @@
|
|||||||
<!--
|
<!--
|
||||||
Copyright (C) 2022 Josh Boudreau <jboudreau@45drives.com>
|
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 GNU General Public License as published by the Free Software Foundation, either version 3
|
||||||
of the License, or (at your option) any later version.
|
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
|
without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
GNU General Public License for more details.
|
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/>.
|
If not, see <https://www.gnu.org/licenses/>.
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<template>
|
<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>
|
</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">
|
Copyright (C) 2022 Josh Boudreau <jboudreau@45drives.com>
|
||||||
<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>
|
|
||||||
|
|
||||||
<!-- This element is to trick the browser into centering the modal contents. -->
|
This file is part of Cockpit Navigator.
|
||||||
<span class="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true">​</span>
|
|
||||||
<TransitionChild
|
Cockpit Navigator is free software: you can redistribute it and/or modify it under the terms
|
||||||
as="template"
|
of the GNU General Public License as published by the Free Software Foundation, either version 3
|
||||||
enter="ease-out duration-300"
|
of the License, or (at your option) any later version.
|
||||||
enter-from="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
|
||||||
enter-to="opacity-100 translate-y-0 sm:scale-100"
|
Cockpit Navigator is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||||
leave="ease-in duration-200"
|
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-from="opacity-100 translate-y-0 sm:scale-100"
|
||||||
leave-to="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
leave-to="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-75">
|
||||||
>
|
|
||||||
<div
|
<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']"
|
: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="block w-[512px]"></div>
|
<div class="card flex flex-col items-stretch overflow-hidden">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<slot name="header">
|
<slot name="header">
|
||||||
<h3 class="text-header">{{ headerText }}</h3>
|
<h3 class="text-header">{{ headerText }}</h3>
|
||||||
</slot>
|
</slot>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body flex flex-row items-center">
|
<div class="card-body flex flex-row items-center">
|
||||||
<div class="shrink-0">
|
|
||||||
<slot name="icon" />
|
<slot name="icon" />
|
||||||
</div>
|
<div class="grow ml-2 only:ml-0 overflow-x-auto">
|
||||||
<div class="grow">
|
|
||||||
<slot />
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-footer button-group-row w-full justify-end">
|
<div class="card-footer button-group-row justify-end">
|
||||||
<button
|
<button v-if="!noCancel" type="button" class="btn btn-secondary" @click="$emit('cancel')">{{
|
||||||
v-if="!noCancel"
|
cancelText
|
||||||
type="button"
|
}}</button>
|
||||||
class="btn btn-secondary"
|
<button type="button" :class="['btn', applyDangerous ? 'btn-danger' : 'btn-primary']"
|
||||||
@click="$emit('cancel')"
|
@click="$emit('apply')" :disabled="disableContinue">{{ applyText }}</button>
|
||||||
>{{ cancelText }}</button>
|
</div>
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
:class="['btn', applyDangerous ? 'btn-danger' : 'btn-primary']"
|
|
||||||
@click="$emit('apply')"
|
|
||||||
:disabled="disableContinue"
|
|
||||||
>{{ applyText }}</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</TransitionChild>
|
</TransitionChild>
|
||||||
</div>
|
</div>
|
||||||
</Dialog>
|
|
||||||
</TransitionRoot>
|
</TransitionRoot>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { Dialog, DialogOverlay, DialogTitle, TransitionChild, TransitionRoot } from '@headlessui/vue';
|
import { TransitionChild, TransitionRoot } from '@headlessui/vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
@ -92,9 +83,6 @@ export default {
|
|||||||
disableContinue: Boolean,
|
disableContinue: Boolean,
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
Dialog,
|
|
||||||
DialogOverlay,
|
|
||||||
DialogTitle,
|
|
||||||
TransitionChild,
|
TransitionChild,
|
||||||
TransitionRoot,
|
TransitionRoot,
|
||||||
},
|
},
|
||||||
|
@ -1,76 +1,62 @@
|
|||||||
|
<!--
|
||||||
|
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>
|
<template>
|
||||||
<!-- Global notification live region, render this permanently at the end of the document -->
|
<div aria-live="assertive"
|
||||||
<div
|
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">
|
||||||
aria-live="assertive"
|
<transition-group tag="div" class="w-full flex flex-col-reverse items-center sm:items-end sm:flex-col space-y-content"
|
||||||
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"
|
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"
|
||||||
<div class="w-full flex flex-col items-center sm:items-end space-y-content">
|
enter-to-class="translate-y-0 opacity-100 scale-100 sm:translate-x-0"
|
||||||
<!-- Notification panel, dynamically insert this into the live region when it needs to be displayed -->
|
leave-active-class="transition-all transform ease-in duration-100"
|
||||||
<transition
|
leave-from-class="opacity-100 scale-100 sm:translate-x-0"
|
||||||
v-for="notification in notificationList"
|
leave-to-class="opacity-0 scale-95 sm:translate-x-8">
|
||||||
:key="notification.id"
|
<div 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"
|
class="max-w-sm w-full shadow-lg pointer-events-auto overflow-hidden bg-default text-default"
|
||||||
@mouseenter="notification.clearTimeouts?.()"
|
@mouseenter="notification.clearTimeouts?.()" @mouseleave="notification.setTimeouts?.()">
|
||||||
@mouseleave="notification.setTimeouts?.()"
|
|
||||||
>
|
|
||||||
<div class="p-4">
|
<div class="p-4">
|
||||||
<div class="flex items-start">
|
<div class="flex items-start">
|
||||||
<div class="flex-shrink-0" aria-hidden="true">
|
<div class="flex-shrink-0" aria-hidden="true">
|
||||||
<ExclamationCircleIcon
|
<ExclamationCircleIcon v-if="notification.level === 'error'" class="icon-error size-icon-lg"
|
||||||
v-if="notification.level === 'error'"
|
aria-hidden="true" />
|
||||||
class="icon-error size-icon-lg"
|
<ExclamationCircleIcon v-else-if="notification.level === 'warning'"
|
||||||
aria-hidden="true"
|
class="icon-warning size-icon-lg" aria-hidden="true" />
|
||||||
/>
|
<CheckCircleIcon v-else-if="notification.level === 'success'"
|
||||||
<ExclamationCircleIcon
|
class="icon-success size-icon-lg" aria-hidden="true" />
|
||||||
v-else-if="notification.level === 'warning'"
|
<MinusCircleIcon v-else-if="notification.level === 'denied'" class="icon-error size-icon-lg"
|
||||||
class="icon-warning size-icon-lg"
|
aria-hidden="true" />
|
||||||
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" />
|
<InformationCircleIcon v-else class="icon-info size-icon-lg" />
|
||||||
</div>
|
</div>
|
||||||
<div class="ml-3 w-0 flex-1 pt-0.5">
|
<div class="ml-3 w-0 flex-1 pt-0.5">
|
||||||
<p class="text-sm font-medium">{{ notification.title }}</p>
|
<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>
|
<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">
|
<div v-if="notification.actions?.length" class="mt-3 flex space-x-7">
|
||||||
<button
|
<button v-for="action in notification.actions" @click="action.callback"
|
||||||
v-for="action in notification.actions"
|
class="rounded-md text-sm font-medium text-primary">
|
||||||
@click="action.callback"
|
|
||||||
class="rounded-md text-sm font-medium text-primary focus:outline-none focus:ring-0 focus:ring-offset-0"
|
|
||||||
>
|
|
||||||
{{ action.text }}
|
{{ action.text }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button @click="notification.show = false" type="button"
|
||||||
@click="notification.show = false"
|
class="rounded-md text-sm font-medium text-secondary">Dismiss</button>
|
||||||
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>
|
</div>
|
||||||
<div class="ml-4 flex-shrink-0 flex">
|
<div class="ml-4 flex-shrink-0 flex">
|
||||||
<button
|
<button @click="notification.show = false"
|
||||||
@click="notification.show = false"
|
class="icon-default">
|
||||||
class="icon-default focus:outline-none focus:ring-0 focus:ring-offset-0"
|
|
||||||
>
|
|
||||||
<span class="sr-only">Close</span>
|
<span class="sr-only">Close</span>
|
||||||
<XIcon class="size-icon" aria-hidden="true" />
|
<XIcon class="size-icon" aria-hidden="true" />
|
||||||
</button>
|
</button>
|
||||||
@ -78,8 +64,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
</transition-group>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -87,7 +72,7 @@
|
|||||||
import { ref, watch, reactive, onUnmounted } from 'vue';
|
import { ref, watch, reactive, onUnmounted } from 'vue';
|
||||||
import { InformationCircleIcon, ExclamationCircleIcon, MinusCircleIcon, CheckCircleIcon } from '@heroicons/vue/outline';
|
import { InformationCircleIcon, ExclamationCircleIcon, MinusCircleIcon, CheckCircleIcon } from '@heroicons/vue/outline';
|
||||||
import { XIcon } from '@heroicons/vue/solid';
|
import { XIcon } from '@heroicons/vue/solid';
|
||||||
import { FIFO, UniqueIDGenerator } from '@45drives/cockpit-helpers';
|
import { FIFO } from '@45drives/cockpit-helpers';
|
||||||
|
|
||||||
/** Notification passed to showNotification
|
/** Notification passed to showNotification
|
||||||
*
|
*
|
||||||
@ -106,13 +91,11 @@ export default {
|
|||||||
setup(props) {
|
setup(props) {
|
||||||
const notificationList = ref([]);
|
const notificationList = ref([]);
|
||||||
|
|
||||||
const uniqueIDGenerator = new UniqueIDGenerator();
|
|
||||||
|
|
||||||
/** Construct new notification and show it
|
/** Construct new notification and show it
|
||||||
*
|
*
|
||||||
* @param {string} title - Header text
|
* @param {string} title - Header text
|
||||||
* @param {string} body - Notification content
|
* @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
|
* @param {number} [timeout=10000] - time to display notification in milliseconds, or zero to display forever
|
||||||
*
|
*
|
||||||
* @returns {Notification} - Object to chain add actions to
|
* @returns {Notification} - Object to chain add actions to
|
||||||
@ -120,7 +103,6 @@ export default {
|
|||||||
const constructNotification = (title, body, level = 'info', timeout = 10000) => {
|
const constructNotification = (title, body, level = 'info', timeout = 10000) => {
|
||||||
const actions = [];
|
const actions = [];
|
||||||
const obj = reactive({
|
const obj = reactive({
|
||||||
show: true,
|
|
||||||
title,
|
title,
|
||||||
body,
|
body,
|
||||||
level,
|
level,
|
||||||
@ -137,8 +119,8 @@ export default {
|
|||||||
obj.actions.push({
|
obj.actions.push({
|
||||||
text,
|
text,
|
||||||
callback: () => {
|
callback: () => {
|
||||||
obj.show = false;
|
|
||||||
callback();
|
callback();
|
||||||
|
obj.removeSelf();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return obj;
|
return obj;
|
||||||
@ -153,27 +135,27 @@ export default {
|
|||||||
*/
|
*/
|
||||||
const showNotificationObj = (notificationObj) => {
|
const showNotificationObj = (notificationObj) => {
|
||||||
notificationObj.show = true;
|
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 = () => {
|
notificationObj.setTimeouts = () => {
|
||||||
if (notificationObj.timeout > 0) {
|
if (notificationObj.timeout > 0) {
|
||||||
notificationObj.timeout1 = setTimeout(
|
notificationObj.removerTimeout = setTimeout(
|
||||||
() => notificationObj.show = false,
|
notificationObj.removeSelf,
|
||||||
notificationObj.timeout
|
notificationObj.timeout
|
||||||
);
|
);
|
||||||
notificationObj.timeout2 = setTimeout(
|
|
||||||
() => {
|
|
||||||
notificationList.value = notificationList.value.filter(obj => obj !== notificationObj);
|
|
||||||
uniqueIDGenerator.release(notificationObj.id);
|
|
||||||
},
|
|
||||||
notificationObj.timeout + 2000
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
notificationObj.clearTimeouts = () => {
|
notificationObj.clearTimeouts = () => {
|
||||||
if (notificationObj.timeout1 !== undefined)
|
if (notificationObj.removerTimeout !== undefined)
|
||||||
clearTimeout(notificationObj.timeout1);
|
clearTimeout(notificationObj.removerTimeout);
|
||||||
if (notificationObj.timeout2 !== undefined)
|
|
||||||
clearTimeout(notificationObj.timeout2);
|
|
||||||
}
|
}
|
||||||
notificationList.value = [notificationObj, ...notificationList.value];
|
notificationList.value = [notificationObj, ...notificationList.value];
|
||||||
if (notificationObj.level === 'error') {
|
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 {
|
return {
|
||||||
notificationList,
|
notificationList,
|
||||||
constructNotification,
|
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>
|
<template>
|
||||||
<div class="shadow border border-default h-full">
|
<div class="shadow border border-default h-full overflow-hidden">
|
||||||
<div
|
<div
|
||||||
v-if="!noHeader"
|
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">
|
<div class="grow">
|
||||||
<slot name="header">{{ headerText }}</slot>
|
<slot name="header">{{ headerText }}</slot>
|
||||||
@ -80,7 +97,7 @@ table.houston-table thead.use-sticky tr th {
|
|||||||
|
|
||||||
table.houston-table th,
|
table.houston-table th,
|
||||||
table.houston-table td {
|
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),
|
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