feat!: refactors UI using faster components and clean up visually (#2381)
* feat: moves to tailwindcss and better component library * update styles * creates toggle component * adds drop down component * cleans up components * removes unused components * uses tailwind for scroll view * removes table component * improves animation * cleans up more styles * uses more tailwind * cleans up more styles with flex * more styles * removes bulma * adds colors * updates modules * fixes bugs * stops importing styles.scss * more clean up * cleans up headers * cleans up title * fixes title * fixes mobile-hidden * fixes shadow * fixes colors * add tailwindcss/nesting * adds more colors * fixes more colors * updates colors * fixes colors * colors * fixes menu on left * menu and modal * menu and modal * fuzzy search * fixes menu on left * remove logs * cleans up search * adds host to search * remove outline from inputs * cleans up left search icon * removes unused styles * fixes docker * removes sass! * cleans up styles * Fixe smobile menu * fixes mobile menu * fixes typecheck * fixes seconday color * adds drop down for container * cleans header css * updates css * fixes other layouts * updates some tests * fixes border * fixes home screen font * fixes top header * fixes tests * fixes fieldlist * fixes complex * cleans up more * removes index * fixes tests * fixes tests * resolves conflicts
@@ -1,3 +1,4 @@
|
||||
module.exports = {
|
||||
printWidth: 120,
|
||||
plugins: ["prettier-plugin-tailwindcss"],
|
||||
};
|
||||
|
||||
@@ -14,7 +14,7 @@ COPY package.json ./
|
||||
RUN pnpm install --offline --ignore-scripts --no-optional
|
||||
|
||||
# Copy assets and translations to build
|
||||
COPY .* vite.config.ts ./
|
||||
COPY .* *.config.ts *.config.js ./
|
||||
COPY assets ./assets
|
||||
COPY locales ./locales
|
||||
COPY public ./public
|
||||
|
||||
@@ -22,5 +22,3 @@ watchEffect(() => {
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss"></style>
|
||||
|
||||
22
assets/auto-imports.d.ts
vendored
@@ -29,9 +29,11 @@ declare global {
|
||||
const controlledRef: typeof import('@vueuse/core')['controlledRef']
|
||||
const createApp: typeof import('vue')['createApp']
|
||||
const createEventHook: typeof import('@vueuse/core')['createEventHook']
|
||||
const createGenericProjection: typeof import('@vueuse/math')['createGenericProjection']
|
||||
const createGlobalState: typeof import('@vueuse/core')['createGlobalState']
|
||||
const createInjectionState: typeof import('@vueuse/core')['createInjectionState']
|
||||
const createPinia: typeof import('pinia')['createPinia']
|
||||
const createProjection: typeof import('@vueuse/math')['createProjection']
|
||||
const createReactiveFn: typeof import('@vueuse/core')['createReactiveFn']
|
||||
const createReusableTemplate: typeof import('@vueuse/core')['createReusableTemplate']
|
||||
const createSharedComposable: typeof import('@vueuse/core')['createSharedComposable']
|
||||
@@ -60,12 +62,14 @@ declare global {
|
||||
const isDefined: typeof import('@vueuse/core')['isDefined']
|
||||
const isMobile: typeof import('./composables/media')['isMobile']
|
||||
const isObject: typeof import('./utils/index')['isObject']
|
||||
const isPinnedContainer: typeof import('./composables/storage')['isPinnedContainer']
|
||||
const isProxy: typeof import('vue')['isProxy']
|
||||
const isReactive: typeof import('vue')['isReactive']
|
||||
const isReadonly: typeof import('vue')['isReadonly']
|
||||
const isRef: typeof import('vue')['isRef']
|
||||
const lightTheme: typeof import('./composables/settings')['lightTheme']
|
||||
const logicAnd: typeof import('@vueuse/math')['logicAnd']
|
||||
const logicNot: typeof import('@vueuse/math')['logicNot']
|
||||
const logicOr: typeof import('@vueuse/math')['logicOr']
|
||||
const makeDestructurable: typeof import('@vueuse/core')['makeDestructurable']
|
||||
const mapActions: typeof import('pinia')['mapActions']
|
||||
const mapGetters: typeof import('pinia')['mapGetters']
|
||||
@@ -141,7 +145,6 @@ declare global {
|
||||
const toRef: typeof import('vue')['toRef']
|
||||
const toRefs: typeof import('vue')['toRefs']
|
||||
const toValue: typeof import('vue')['toValue']
|
||||
const togglePinnedContainer: typeof import('./composables/storage')['togglePinnedContainer']
|
||||
const triggerRef: typeof import('vue')['triggerRef']
|
||||
const tryOnBeforeMount: typeof import('@vueuse/core')['tryOnBeforeMount']
|
||||
const tryOnBeforeUnmount: typeof import('@vueuse/core')['tryOnBeforeUnmount']
|
||||
@@ -151,6 +154,7 @@ declare global {
|
||||
const unref: typeof import('vue')['unref']
|
||||
const unrefElement: typeof import('@vueuse/core')['unrefElement']
|
||||
const until: typeof import('@vueuse/core')['until']
|
||||
const useAbs: typeof import('@vueuse/math')['useAbs']
|
||||
const useActiveElement: typeof import('@vueuse/core')['useActiveElement']
|
||||
const useAnimate: typeof import('@vueuse/core')['useAnimate']
|
||||
const useArrayDifference: typeof import('@vueuse/core')['useArrayDifference']
|
||||
@@ -168,6 +172,7 @@ declare global {
|
||||
const useAsyncQueue: typeof import('@vueuse/core')['useAsyncQueue']
|
||||
const useAsyncState: typeof import('@vueuse/core')['useAsyncState']
|
||||
const useAttrs: typeof import('vue')['useAttrs']
|
||||
const useAverage: typeof import('@vueuse/math')['useAverage']
|
||||
const useBase64: typeof import('@vueuse/core')['useBase64']
|
||||
const useBattery: typeof import('@vueuse/core')['useBattery']
|
||||
const useBluetooth: typeof import('@vueuse/core')['useBluetooth']
|
||||
@@ -175,6 +180,8 @@ declare global {
|
||||
const useBroadcastChannel: typeof import('@vueuse/core')['useBroadcastChannel']
|
||||
const useBrowserLocation: typeof import('@vueuse/core')['useBrowserLocation']
|
||||
const useCached: typeof import('@vueuse/core')['useCached']
|
||||
const useCeil: typeof import('@vueuse/math')['useCeil']
|
||||
const useClamp: typeof import('@vueuse/math')['useClamp']
|
||||
const useClipboard: typeof import('@vueuse/core')['useClipboard']
|
||||
const useCloned: typeof import('@vueuse/core')['useCloned']
|
||||
const useColorMode: typeof import('@vueuse/core')['useColorMode']
|
||||
@@ -213,6 +220,7 @@ declare global {
|
||||
const useFetch: typeof import('@vueuse/core')['useFetch']
|
||||
const useFileDialog: typeof import('@vueuse/core')['useFileDialog']
|
||||
const useFileSystemAccess: typeof import('@vueuse/core')['useFileSystemAccess']
|
||||
const useFloor: typeof import('@vueuse/math')['useFloor']
|
||||
const useFocus: typeof import('@vueuse/core')['useFocus']
|
||||
const useFocusWithin: typeof import('@vueuse/core')['useFocusWithin']
|
||||
const useFps: typeof import('@vueuse/core')['useFps']
|
||||
@@ -234,10 +242,13 @@ declare global {
|
||||
const useLogStream: typeof import('./composables/eventsource')['useLogStream']
|
||||
const useMagicKeys: typeof import('@vueuse/core')['useMagicKeys']
|
||||
const useManualRefHistory: typeof import('@vueuse/core')['useManualRefHistory']
|
||||
const useMath: typeof import('@vueuse/math')['useMath']
|
||||
const useMax: typeof import('@vueuse/math')['useMax']
|
||||
const useMediaControls: typeof import('@vueuse/core')['useMediaControls']
|
||||
const useMediaQuery: typeof import('@vueuse/core')['useMediaQuery']
|
||||
const useMemoize: typeof import('@vueuse/core')['useMemoize']
|
||||
const useMemory: typeof import('@vueuse/core')['useMemory']
|
||||
const useMin: typeof import('@vueuse/math')['useMin']
|
||||
const useMounted: typeof import('@vueuse/core')['useMounted']
|
||||
const useMouse: typeof import('@vueuse/core')['useMouse']
|
||||
const useMouseInElement: typeof import('@vueuse/core')['useMouseInElement']
|
||||
@@ -257,15 +268,18 @@ declare global {
|
||||
const usePointer: typeof import('@vueuse/core')['usePointer']
|
||||
const usePointerLock: typeof import('@vueuse/core')['usePointerLock']
|
||||
const usePointerSwipe: typeof import('@vueuse/core')['usePointerSwipe']
|
||||
const usePrecision: typeof import('@vueuse/math')['usePrecision']
|
||||
const usePreferredColorScheme: typeof import('@vueuse/core')['usePreferredColorScheme']
|
||||
const usePreferredContrast: typeof import('@vueuse/core')['usePreferredContrast']
|
||||
const usePreferredDark: typeof import('@vueuse/core')['usePreferredDark']
|
||||
const usePreferredLanguages: typeof import('@vueuse/core')['usePreferredLanguages']
|
||||
const usePreferredReducedMotion: typeof import('@vueuse/core')['usePreferredReducedMotion']
|
||||
const usePrevious: typeof import('@vueuse/core')['usePrevious']
|
||||
const useProjection: typeof import('@vueuse/math')['useProjection']
|
||||
const useRafFn: typeof import('@vueuse/core')['useRafFn']
|
||||
const useRefHistory: typeof import('@vueuse/core')['useRefHistory']
|
||||
const useResizeObserver: typeof import('@vueuse/core')['useResizeObserver']
|
||||
const useRound: typeof import('@vueuse/math')['useRound']
|
||||
const useRoute: typeof import('vue-router')['useRoute']
|
||||
const useRouter: typeof import('vue-router')['useRouter']
|
||||
const useScreenOrientation: typeof import('@vueuse/core')['useScreenOrientation']
|
||||
@@ -285,6 +299,7 @@ declare global {
|
||||
const useStorage: typeof import('@vueuse/core')['useStorage']
|
||||
const useStorageAsync: typeof import('@vueuse/core')['useStorageAsync']
|
||||
const useStyleTag: typeof import('@vueuse/core')['useStyleTag']
|
||||
const useSum: typeof import('@vueuse/math')['useSum']
|
||||
const useSupported: typeof import('@vueuse/core')['useSupported']
|
||||
const useSwipe: typeof import('@vueuse/core')['useSwipe']
|
||||
const useTemplateRefsList: typeof import('@vueuse/core')['useTemplateRefsList']
|
||||
@@ -304,6 +319,7 @@ declare global {
|
||||
const useToString: typeof import('@vueuse/core')['useToString']
|
||||
const useToggle: typeof import('@vueuse/core')['useToggle']
|
||||
const useTransition: typeof import('@vueuse/core')['useTransition']
|
||||
const useTrunc: typeof import('@vueuse/math')['useTrunc']
|
||||
const useUrlSearchParams: typeof import('@vueuse/core')['useUrlSearchParams']
|
||||
const useUserMedia: typeof import('@vueuse/core')['useUserMedia']
|
||||
const useVModel: typeof import('@vueuse/core')['useVModel']
|
||||
@@ -480,7 +496,6 @@ declare module 'vue' {
|
||||
readonly toRef: UnwrapRef<typeof import('vue')['toRef']>
|
||||
readonly toRefs: UnwrapRef<typeof import('vue')['toRefs']>
|
||||
readonly toValue: UnwrapRef<typeof import('vue')['toValue']>
|
||||
readonly togglePinnedContainer: UnwrapRef<typeof import('./composables/storage')['togglePinnedContainer']>
|
||||
readonly triggerRef: UnwrapRef<typeof import('vue')['triggerRef']>
|
||||
readonly tryOnBeforeMount: UnwrapRef<typeof import('@vueuse/core')['tryOnBeforeMount']>
|
||||
readonly tryOnBeforeUnmount: UnwrapRef<typeof import('@vueuse/core')['tryOnBeforeUnmount']>
|
||||
@@ -813,7 +828,6 @@ declare module '@vue/runtime-core' {
|
||||
readonly toRef: UnwrapRef<typeof import('vue')['toRef']>
|
||||
readonly toRefs: UnwrapRef<typeof import('vue')['toRefs']>
|
||||
readonly toValue: UnwrapRef<typeof import('vue')['toValue']>
|
||||
readonly togglePinnedContainer: UnwrapRef<typeof import('./composables/storage')['togglePinnedContainer']>
|
||||
readonly triggerRef: UnwrapRef<typeof import('vue')['triggerRef']>
|
||||
readonly tryOnBeforeMount: UnwrapRef<typeof import('@vueuse/core')['tryOnBeforeMount']>
|
||||
readonly tryOnBeforeUnmount: UnwrapRef<typeof import('@vueuse/core')['tryOnBeforeUnmount']>
|
||||
|
||||
5
assets/components.d.ts
vendored
@@ -13,6 +13,7 @@ declare module 'vue' {
|
||||
'Carbon:macShift': typeof import('~icons/carbon/mac-shift')['default']
|
||||
'Carbon:star': typeof import('~icons/carbon/star')['default']
|
||||
'Carbon:starFilled': typeof import('~icons/carbon/star-filled')['default']
|
||||
'Cil:check': typeof import('~icons/cil/check')['default']
|
||||
'Cil:checkCircle': typeof import('~icons/cil/check-circle')['default']
|
||||
'Cil:circle': typeof import('~icons/cil/circle')['default']
|
||||
'Cil:columns': typeof import('~icons/cil/columns')['default']
|
||||
@@ -28,13 +29,14 @@ declare module 'vue' {
|
||||
DateTime: typeof import('./components/common/DateTime.vue')['default']
|
||||
DistanceTime: typeof import('./components/common/DistanceTime.vue')['default']
|
||||
DockerEventLogItem: typeof import('./components/LogViewer/DockerEventLogItem.vue')['default']
|
||||
Dropdown: typeof import('./components/common/Dropdown.vue')['default']
|
||||
DropdownMenu: typeof import('./components/DropdownMenu.vue')['default']
|
||||
FieldList: typeof import('./components/LogViewer/FieldList.vue')['default']
|
||||
FuzzySearchModal: typeof import('./components/FuzzySearchModal.vue')['default']
|
||||
'Ic:sharpFindInPage': typeof import('~icons/ic/sharp-find-in-page')['default']
|
||||
'Ic:sharpKeyboardReturn': typeof import('~icons/ic/sharp-keyboard-return')['default']
|
||||
InfiniteLoader: typeof import('./components/InfiniteLoader.vue')['default']
|
||||
KeyShortcut: typeof import('./components/KeyShortcut.vue')['default']
|
||||
KeyShortcut: typeof import('./components/common/KeyShortcut.vue')['default']
|
||||
LogActionsToolbar: typeof import('./components/LogViewer/LogActionsToolbar.vue')['default']
|
||||
LogContainer: typeof import('./components/LogViewer/LogContainer.vue')['default']
|
||||
LogDate: typeof import('./components/LogViewer/LogDate.vue')['default']
|
||||
@@ -75,6 +77,7 @@ declare module 'vue' {
|
||||
StatMonitor: typeof import('./components/LogViewer/StatMonitor.vue')['default']
|
||||
StatSparkline: typeof import('./components/LogViewer/StatSparkline.vue')['default']
|
||||
Tag: typeof import('./components/common/Tag.vue')['default']
|
||||
Toggle: typeof import('./components/common/Toggle.vue')['default']
|
||||
ZigZag: typeof import('./components/LogViewer/ZigZag.vue')['default']
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="is-relative">
|
||||
<div class="bar"></div>
|
||||
<div class="is-overlay">
|
||||
<div class="relative">
|
||||
<div class="bar h-7 origin-left rounded-br rounded-tr bg-primary transition-transform"></div>
|
||||
<div class="absolute inset-0 flex flex-col justify-center px-2 text-sm">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</div>
|
||||
@@ -15,17 +15,6 @@ const minValue = computed(() => Math.min(value, 1));
|
||||
|
||||
<style scoped>
|
||||
.bar {
|
||||
height: 1.5em;
|
||||
background-color: var(--primary-color);
|
||||
transform-origin: left;
|
||||
transform: scaleX(v-bind(minValue));
|
||||
transition: transform 0.2s ease-out;
|
||||
border-top-right-radius: 0.2em;
|
||||
border-bottom-right-radius: 0.2em;
|
||||
}
|
||||
|
||||
.is-overlay {
|
||||
font-size: 0.9em;
|
||||
padding: 0 0.5em;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
!
|
||||
<template>
|
||||
<table class="table is-fullwidth">
|
||||
<table class="table table-lg bg-base">
|
||||
<thead>
|
||||
<tr :data-direction="direction > 0 ? 'asc' : 'desc'">
|
||||
<th
|
||||
@@ -10,12 +10,10 @@
|
||||
:class="{ 'selected-sort': key === sortField }"
|
||||
v-show="isVisible(key)"
|
||||
>
|
||||
<a>
|
||||
<span class="icon-text">
|
||||
<span>{{ $t(value.label) }}</span>
|
||||
<span class="icon">
|
||||
<mdi:arrow-up />
|
||||
</span>
|
||||
<a class="inline-flex cursor-pointer gap-2 text-sm uppercase">
|
||||
<span>{{ $t(value.label) }}</span>
|
||||
<span class="h-4" data-icon>
|
||||
<mdi:arrow-up />
|
||||
</span>
|
||||
</a>
|
||||
</th>
|
||||
@@ -46,15 +44,18 @@
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<nav class="pagination is-right" role="navigation" aria-label="pagination" v-if="isPaginated">
|
||||
<ul class="pagination-list">
|
||||
<li v-for="i in totalPages">
|
||||
<a class="pagination-link" :class="{ 'is-current': i === currentPage }" @click.prevent="currentPage = i">{{
|
||||
i
|
||||
}}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
<div class="p-4 text-center">
|
||||
<nav class="join" v-if="isPaginated">
|
||||
<button
|
||||
v-for="i in totalPages"
|
||||
class="btn join-item"
|
||||
:class="{ 'btn-primary': i === currentPage }"
|
||||
@click="currentPage = i"
|
||||
>
|
||||
{{ i }}
|
||||
</button>
|
||||
</nav>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
@@ -137,19 +138,23 @@ function isVisible(field: keys) {
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.icon {
|
||||
<style lang="postcss" scoped>
|
||||
[data-icon] {
|
||||
display: none;
|
||||
transition: transform 0.2s ease-in-out;
|
||||
[data-direction="desc"] & {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
}
|
||||
.selected-sort {
|
||||
font-weight: bold;
|
||||
border-color: var(--primary-color);
|
||||
.icon {
|
||||
display: inline-block;
|
||||
|
||||
th {
|
||||
@apply border-b-2 border-base-lighter;
|
||||
&.selected-sort {
|
||||
font-weight: bold;
|
||||
@apply border-primary;
|
||||
[data-icon] {
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -159,4 +164,8 @@ tbody td {
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
a {
|
||||
@apply hover:text-primary;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="dropdown is-hoverable">
|
||||
<div class="is-hoverable dropdown">
|
||||
<div class="dropdown-trigger">
|
||||
<slot name="trigger">
|
||||
<button class="button" aria-haspopup="true" aria-controls="dropdown-menu">
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
<script lang="ts" setup></script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
<style lang="postcss" scoped>
|
||||
.minimal .button {
|
||||
background-color: rgba(0, 0, 0, 0);
|
||||
border: none;
|
||||
|
||||
@@ -1,50 +1,57 @@
|
||||
<template>
|
||||
<div class="panel">
|
||||
<o-autocomplete
|
||||
ref="autocomplete"
|
||||
v-model="query"
|
||||
:placeholder="$t('placeholder.search-containers')"
|
||||
open-on-focus
|
||||
keep-first
|
||||
expanded
|
||||
:data="data"
|
||||
@select="selected"
|
||||
>
|
||||
<template #default="{ option: item }">
|
||||
<div class="media">
|
||||
<div class="media-left">
|
||||
<span class="icon is-small" :class="item.state">
|
||||
<octicon:container-24 />
|
||||
</span>
|
||||
<div class="dropdown dropdown-open w-full">
|
||||
<div class="input input-primary flex h-auto items-center">
|
||||
<mdi:light-magnify class="flex h-8 w-8" />
|
||||
<input
|
||||
tabindex="0"
|
||||
class="input input-ghost input-lg flex-1 px-1"
|
||||
ref="input"
|
||||
@keydown.down="selectedIndex = Math.min(selectedIndex + 1, data.length - 1)"
|
||||
@keydown.up="selectedIndex = Math.max(selectedIndex - 1, 0)"
|
||||
@keypress.enter="selected(data[selectedIndex])"
|
||||
v-model="query"
|
||||
:placeholder="$t('placeholder.search-containers')"
|
||||
/>
|
||||
<mdi:keyboard-esc class="flex" />
|
||||
</div>
|
||||
<ul tabindex="0" class="menu dropdown-content rounded-box !relative mt-2 w-full bg-base-lighter p-2">
|
||||
<li v-for="(item, index) in data">
|
||||
<a
|
||||
class="grid auto-cols-max grid-cols-[min-content,auto] gap-2 py-4"
|
||||
@click.prevent="selected(item)"
|
||||
@mouseenter="selectedIndex = index"
|
||||
:class="index === selectedIndex ? 'focus' : ''"
|
||||
>
|
||||
<div :class="{ 'text-primary': item.state === 'running' }">
|
||||
<octicon:container-24 />
|
||||
</div>
|
||||
<div class="media-content">{{ item.host }} / {{ item.name }}</div>
|
||||
<div class="media-right">
|
||||
<span
|
||||
class="icon is-small column-icon"
|
||||
@click.stop.prevent="addColumn(item)"
|
||||
:title="$t('tooltip.pin-column')"
|
||||
>
|
||||
<cil:columns />
|
||||
</span>
|
||||
<div class="truncate">
|
||||
<span class="font-light">{{ item.host }}</span> / {{ item.name }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</o-autocomplete>
|
||||
<distance-time :date="item.created" class="ml-auto text-xs font-light" />
|
||||
<a @click.stop.prevent="addColumn(item)" :title="$t('tooltip.pin-column')" class="hover:text-secondary">
|
||||
<ic:sharp-keyboard-return v-if="index === selectedIndex" />
|
||||
<cil:columns v-else />
|
||||
</a>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { Container } from "@/models/Container";
|
||||
import { useFuse } from "@vueuse/integrations/useFuse";
|
||||
|
||||
const { maxResults: resultLimit = 20 } = defineProps<{
|
||||
const { maxResults: resultLimit = 5 } = defineProps<{
|
||||
maxResults?: number;
|
||||
}>();
|
||||
|
||||
const close = defineEmit();
|
||||
|
||||
const query = ref("");
|
||||
const autocomplete = ref<HTMLElement>();
|
||||
const input = ref<HTMLInputElement>();
|
||||
const selectedIndex = ref(0);
|
||||
|
||||
const router = useRouter();
|
||||
const store = useContainerStore();
|
||||
const { containers } = storeToRefs(store);
|
||||
@@ -62,7 +69,7 @@ const list = computed(() => {
|
||||
});
|
||||
|
||||
const { results } = useFuse(query, list, {
|
||||
fuseOptions: { keys: ["name"], includeScore: true },
|
||||
fuseOptions: { keys: ["name", "host"], includeScore: true },
|
||||
resultLimit,
|
||||
matchAllWhenSearchEmpty: true,
|
||||
});
|
||||
@@ -82,62 +89,28 @@ const data = computed(() => {
|
||||
return 0;
|
||||
}
|
||||
})
|
||||
.map(({ item }) => item);
|
||||
.map(({ item }) => item)
|
||||
.slice(0, resultLimit);
|
||||
});
|
||||
watchOnce(autocomplete, () => autocomplete.value?.focus());
|
||||
|
||||
watch(query, (data) => {
|
||||
if (data.length > 0) {
|
||||
selectedIndex.value = 0;
|
||||
}
|
||||
});
|
||||
|
||||
onMounted(() => input.value?.focus());
|
||||
|
||||
function selected({ id }: { id: string }) {
|
||||
router.push({ name: "container-id", params: { id } });
|
||||
query.value = "";
|
||||
close();
|
||||
}
|
||||
function addColumn(container: Container) {
|
||||
function addColumn(container: { id: string }) {
|
||||
store.appendActiveContainer(container);
|
||||
query.value = "";
|
||||
close();
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.panel {
|
||||
min-height: 400px;
|
||||
width: 580px;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 768px) {
|
||||
.panel {
|
||||
min-height: 200px;
|
||||
width: auto;
|
||||
margin-left: 0.25rem !important;
|
||||
margin-right: 0.25rem !important;
|
||||
}
|
||||
}
|
||||
|
||||
.running {
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
||||
.exited {
|
||||
color: var(--scheme-main-ter);
|
||||
}
|
||||
|
||||
.column-icon {
|
||||
&:hover {
|
||||
color: var(--secondary-color);
|
||||
}
|
||||
}
|
||||
|
||||
:deep(a.dropdown-item) {
|
||||
padding-right: 1em;
|
||||
|
||||
.media-right {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
&:hover .media-right {
|
||||
visibility: visible;
|
||||
}
|
||||
}
|
||||
|
||||
.icon {
|
||||
vertical-align: middle;
|
||||
}
|
||||
</style>
|
||||
<style scoped lang="postcss"></style>
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
<template>
|
||||
<div ref="root" class="infinte-loader">
|
||||
<div class="spinner" v-show="isLoading">
|
||||
<div class="bounce1"></div>
|
||||
<div class="bounce2"></div>
|
||||
<div class="bounce3"></div>
|
||||
</div>
|
||||
<div ref="root" class="flex min-h-[1px] justify-center">
|
||||
<span class="loading loading-bars loading-md mt-4 text-primary" v-show="isLoading"></span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -33,41 +29,3 @@ const observer = new IntersectionObserver(async (entries) => {
|
||||
onMounted(() => observer.observe(root.value!));
|
||||
onUnmounted(() => observer.disconnect());
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.infinte-loader {
|
||||
min-height: 1px;
|
||||
}
|
||||
.spinner {
|
||||
margin: 10px auto 0;
|
||||
width: 70px;
|
||||
text-align: center;
|
||||
|
||||
& > div {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
background-color: var(--primary-color);
|
||||
border-radius: 100%;
|
||||
display: inline-block;
|
||||
animation: sk-bouncedelay 0.8s infinite ease-in-out both;
|
||||
}
|
||||
& .bounce1 {
|
||||
animation-delay: -0.32s;
|
||||
}
|
||||
|
||||
& .bounce2 {
|
||||
animation-delay: -0.16s;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes sk-bouncedelay {
|
||||
0%,
|
||||
80%,
|
||||
100% {
|
||||
transform: scale(0);
|
||||
}
|
||||
40% {
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
<template>
|
||||
<span class="icon-text">
|
||||
<span class="icon mx-0" v-if="modifiers.includes('shift')">
|
||||
<carbon:mac-shift />
|
||||
</span>
|
||||
<span class="icon mx-0" v-if="modifiers.includes('meta')">
|
||||
<ph:command v-if="isMac" />
|
||||
<ph:control-bold v-else />
|
||||
</span>
|
||||
<kbd class="is-uppercase is-family-sans-serif ml-1">{{ char }}</kbd>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
const isMac = /(Mac|iPhone|iPod|iPad)/i.test(navigator.userAgent);
|
||||
</script>
|
||||
<script lang="ts" setup>
|
||||
const { modifiers = ["meta"], char } = defineProps<{ char: string; modifiers?: ("^" | "meta" | "shift")[] }>();
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.icon {
|
||||
width: unset;
|
||||
}
|
||||
</style>
|
||||
@@ -1,25 +1,24 @@
|
||||
<template>
|
||||
<div class="columns is-1 is-variable is-mobile">
|
||||
<div class="column is-narrow" v-if="showStd">
|
||||
<div class="flex gap-x-2">
|
||||
<div v-if="showStd">
|
||||
<log-std :std="logEntry.std"></log-std>
|
||||
</div>
|
||||
<div class="column is-narrow" v-if="showTimestamp">
|
||||
<div v-if="showTimestamp">
|
||||
<log-date :date="logEntry.date"></log-date>
|
||||
</div>
|
||||
<div class="column is-narrow is-flex">
|
||||
<div class="flex">
|
||||
<log-level :level="logEntry.level"></log-level>
|
||||
</div>
|
||||
<div class="column">
|
||||
<ul class="fields" :class="{ expanded }" @click="expandToggle()">
|
||||
<li v-for="(value, name) in validValues">
|
||||
<span class="has-text-grey">{{ name }}=</span
|
||||
><span class="has-text-weight-bold" v-if="value === null"><null></span>
|
||||
<div>
|
||||
<ul class="fields cursor-pointer space-x-4" :class="{ expanded }" @click="expandToggle()">
|
||||
<li v-for="(value, name) in validValues" class="inline-block">
|
||||
<span class="text-light">{{ name }}=</span><span class="font-bold" v-if="value === null"><null></span>
|
||||
<template v-else-if="Array.isArray(value)">
|
||||
<span class="has-text-weight-bold" v-html="markSearch(JSON.stringify(value))"> </span>
|
||||
<span class="font-bold" v-html="markSearch(JSON.stringify(value))"> </span>
|
||||
</template>
|
||||
<span class="has-text-weight-bold" v-html="markSearch(value)" v-else></span>
|
||||
<span class="font-bold" v-html="markSearch(value)" v-else></span>
|
||||
</li>
|
||||
<li class="has-text-grey" v-if="Object.keys(validValues).length === 0">all values are hidden</li>
|
||||
<li class="text-light" v-if="Object.keys(validValues).length === 0">all values are hidden</li>
|
||||
</ul>
|
||||
<field-list :fields="logEntry.unfilteredMessage" :expanded="expanded" :visible-keys="visibleKeys"></field-list>
|
||||
</div>
|
||||
@@ -42,19 +41,15 @@ const validValues = computed(() => {
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
<style lang="postcss" scoped>
|
||||
.text-light {
|
||||
@apply text-base-content/70;
|
||||
}
|
||||
.fields {
|
||||
display: inline-block;
|
||||
list-style: none;
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
|
||||
&::after {
|
||||
content: "expand json";
|
||||
color: var(--secondary-color);
|
||||
display: inline-block;
|
||||
margin-left: 0.5em;
|
||||
@apply ml-2 inline-block text-secondary;
|
||||
font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
|
||||
}
|
||||
}
|
||||
@@ -64,13 +59,5 @@ const validValues = computed(() => {
|
||||
content: "collapse json";
|
||||
}
|
||||
}
|
||||
|
||||
li {
|
||||
display: inline-block;
|
||||
|
||||
& + li {
|
||||
margin-left: 1em;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="icon is-small health" :health="health" v-if="health" :title="health">
|
||||
<div class="inline-flex h-4 w-4" :health="health" v-if="health" :title="health">
|
||||
<cil:check-circle v-if="health == 'healthy'" />
|
||||
<cil:x-circle v-else-if="health == 'unhealthy'" />
|
||||
<cil:circle v-else />
|
||||
@@ -14,14 +14,12 @@ defineProps<{
|
||||
}>();
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.health {
|
||||
&[health="unhealthy"] {
|
||||
color: var(--red-color);
|
||||
}
|
||||
<style lang="postcss" scoped>
|
||||
[health="unhealthy"] {
|
||||
@apply text-red;
|
||||
}
|
||||
|
||||
&[health="healthy"] {
|
||||
color: var(--green-color);
|
||||
}
|
||||
[health="healthy"] {
|
||||
@apply text-green;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
<template>
|
||||
<div>
|
||||
<span class="has-text-weight-light"> RUNNING </span>
|
||||
<span class="has-text-weight-semibold">
|
||||
<span class="font-light capitalize"> RUNNING </span>
|
||||
<span class="font-semibold">
|
||||
<distance-time :date="container.created" strict :suffix="false"></distance-time>
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<span class="has-text-weight-light"> LOAD </span>
|
||||
<span class="has-text-weight-semibold"> {{ container.stat.cpu }}% </span>
|
||||
<span class="font-light capitalize"> Load </span>
|
||||
<span class="font-semibold"> {{ container.stat.cpu }}% </span>
|
||||
</div>
|
||||
<div>
|
||||
<span class="has-text-weight-light"> MEM </span>
|
||||
<span class="has-text-weight-semibold"> {{ formatBytes(container.stat.memoryUsage) }} </span>
|
||||
<span class="font-light capitalize"> MEM </span>
|
||||
<span class="font-semibold"> {{ formatBytes(container.stat.memoryUsage) }} </span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -22,5 +22,3 @@ const { container } = defineProps<{
|
||||
container: Container;
|
||||
}>();
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
|
||||
@@ -1,17 +1,7 @@
|
||||
<template>
|
||||
<div class="is-size-7 is-uppercase columns is-marginless is-mobile is-vcentered" v-if="container.stat">
|
||||
<stat-monitor
|
||||
class="column is-narrow"
|
||||
:data="memoryData"
|
||||
label="mem"
|
||||
:stat-value="formatBytes(unref(container.stat).memoryUsage)"
|
||||
></stat-monitor>
|
||||
<stat-monitor
|
||||
class="column is-narrow"
|
||||
:data="cpuData"
|
||||
label="load"
|
||||
:stat-value="unref(container.stat).cpu + '%'"
|
||||
></stat-monitor>
|
||||
<div class="flex gap-4" v-if="container.stat">
|
||||
<stat-monitor :data="memoryData" label="mem" :stat-value="formatBytes(unref(container.stat).memoryUsage)" />
|
||||
<stat-monitor :data="cpuData" label="load" :stat-value="unref(container.stat).cpu + '%'" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -47,24 +37,3 @@ const memoryData = computedWithControl(
|
||||
},
|
||||
);
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.has-border {
|
||||
border: 1px solid var(--primary-color);
|
||||
border-radius: 3px;
|
||||
padding: 1px 1px 0 1px;
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
padding-top: 0.25em;
|
||||
}
|
||||
|
||||
.has-background-body-color {
|
||||
background-color: var(--body-background-color);
|
||||
}
|
||||
|
||||
.is-top-left {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0.75em;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,19 +1,24 @@
|
||||
<template>
|
||||
<div class="columns is-marginless has-text-weight-bold is-family-monospace">
|
||||
<div class="column is-ellipsis">
|
||||
<container-health :health="container.health" v-if="container.health"></container-health>
|
||||
<div class="name">
|
||||
<span v-if="config.hosts.length > 1" class="host has-text-weight-light is-hidden-mobile"
|
||||
>{{ container.hostLabel }}<span class="has-text-weight-light mx-2">/</span></span
|
||||
><span class="">{{ container.name }}</span
|
||||
><span v-if="container.isSwarm" class="swarm-id is-hidden-mobile is-ellipsis">{{ container.swarmId }}</span>
|
||||
<div class="flex flex-1 items-center gap-2 truncate">
|
||||
<container-health :health="container.health" v-if="container.health"></container-health>
|
||||
<div class="inline-flex font-mono text-sm">
|
||||
<div v-if="config.hosts.length > 1" class="mobile-hidden font-thin">
|
||||
{{ container.hostLabel }}<span class="mx-2">/</span>
|
||||
</div>
|
||||
<div class="font-semibold">{{ container.name }}</div>
|
||||
<div
|
||||
class="mobile-hidden max-w-[1.5em] truncate transition-[max-width] hover:max-w-[400px]"
|
||||
v-if="container.isSwarm"
|
||||
>
|
||||
{{ container.swarmId }}
|
||||
</div>
|
||||
<tag class="is-hidden-mobile">{{ container.image.replace(/@sha.*/, "") }}</tag>
|
||||
<span class="icon is-clickable" @click="togglePinnedContainer(container.storageKey)">
|
||||
<carbon:star-filled v-if="pinned" />
|
||||
<carbon:star v-else />
|
||||
</span>
|
||||
</div>
|
||||
<tag class="mobile-hidden font-mono" size="small">{{ container.image.replace(/@sha.*/, "") }}</tag>
|
||||
<label class="swap swap-rotate">
|
||||
<input type="checkbox" v-model="pinned" />
|
||||
<carbon:star-filled class="swap-on" />
|
||||
<carbon:star class="swap-off" />
|
||||
</label>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -22,29 +27,14 @@ import { Container } from "@/models/Container";
|
||||
import { type ComputedRef } from "vue";
|
||||
|
||||
const container = inject("container") as ComputedRef<Container>;
|
||||
const pinned = computed(() => pinnedContainers.value.has(container.value.storageKey));
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.icon {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.name {
|
||||
display: inline-flex;
|
||||
.swarm-id {
|
||||
max-width: 1.5em;
|
||||
display: inline-block;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
transition: max-width 0.2s ease-in-out;
|
||||
will-change: max-width;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.swarm-id {
|
||||
max-width: 400px;
|
||||
const pinned = computed({
|
||||
get: () => pinnedContainers.value.has(container.value.storageKey),
|
||||
set: (value) => {
|
||||
if (value) {
|
||||
pinnedContainers.value.add(container.value.storageKey);
|
||||
} else {
|
||||
pinnedContainers.value.delete(container.value.storageKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<span class="text" :data-event="logEntry.event" v-html="logEntry.message"></span>
|
||||
<span class="whitespace-pre-wrap" :data-event="logEntry.event" v-html="logEntry.message"></span>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { DockerEventLogEntry } from "@/models/LogEntry";
|
||||
@@ -9,16 +9,11 @@ defineProps<{
|
||||
}>();
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
span {
|
||||
&[data-event="container-stopped"] {
|
||||
color: #f14668;
|
||||
}
|
||||
&[data-event="container-started"] {
|
||||
color: hsl(141, 53%, 53%);
|
||||
}
|
||||
&.text {
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
<style lang="postcss" scoped>
|
||||
[data-event="container-stopped"] {
|
||||
@apply text-red;
|
||||
}
|
||||
[data-event="container-started"] {
|
||||
@apply text-green;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<template>
|
||||
<ul v-if="expanded" ref="root">
|
||||
<ul v-if="expanded" ref="root" class="ml-8">
|
||||
<li v-for="(value, name) in fields">
|
||||
<template v-if="isObject(value)">
|
||||
<span class="has-text-grey">{{ name }}=</span>
|
||||
<span class="text-light">{{ name }}=</span>
|
||||
<field-list
|
||||
:fields="value"
|
||||
:parent-key="parentKey.concat(name)"
|
||||
@@ -12,15 +12,15 @@
|
||||
</template>
|
||||
<template v-else-if="Array.isArray(value)">
|
||||
<a @click="toggleField(name)"> {{ hasField(name) ? "remove" : "add" }} </a>
|
||||
<span class="has-text-grey">{{ name }}=</span>[
|
||||
<span class="has-text-weight-bold" v-for="(item, index) in value">
|
||||
<span class="text-light">{{ name }}=</span>[
|
||||
<span class="font-bold" v-for="(item, index) in value">
|
||||
<span v-html="JSON.stringify(item)"></span><span v-if="index !== value.length - 1">,</span>
|
||||
</span>
|
||||
]
|
||||
</template>
|
||||
<template v-else>
|
||||
<a @click="toggleField(name)"> {{ hasField(name) ? "remove" : "add" }} </a>
|
||||
<span class="has-text-grey">{{ name }}=</span><span class="has-text-weight-bold" v-html="value"></span>
|
||||
<span class="text-light">{{ name }}=</span><span class="font-bold" v-html="value"></span>
|
||||
</template>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -68,8 +68,8 @@ function fieldIndex(field: string) {
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
ul {
|
||||
margin-left: 2em;
|
||||
<style scoped lang="postcss">
|
||||
.text-light {
|
||||
@apply text-base-content/70;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,114 +1,72 @@
|
||||
<template>
|
||||
<dropdown-menu class="is-right">
|
||||
<template #trigger>
|
||||
<button class="button" aria-haspopup="true" aria-controls="dropdown-menu">
|
||||
<span class="icon">
|
||||
<carbon:circle-solid class="is-red is-small" v-if="streamConfig.stderr" />
|
||||
<carbon:circle-solid class="is-blue is-small" v-if="streamConfig.stdout" />
|
||||
</span>
|
||||
</button>
|
||||
</template>
|
||||
<a class="dropdown-item" @click="clear()">
|
||||
<div class="level is-justify-content-start">
|
||||
<div class="level-left">
|
||||
<div class="level-item">
|
||||
<octicon:trash-24 />
|
||||
</div>
|
||||
</div>
|
||||
<div class="level-right is-justify-content-space-between is-flex-grow-1">
|
||||
<div class="level-item">{{ $t("toolbar.clear") }}</div>
|
||||
<div class="level-item"><key-shortcut char="k" :modifiers="['shift', 'meta']"></key-shortcut></div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
<a class="dropdown-item" :href="`${base}/api/logs/download/${container.host}/${container.id}`">
|
||||
<div class="level is-justify-content-start">
|
||||
<div class="level-left">
|
||||
<div class="level-item">
|
||||
<octicon:download-24 />
|
||||
</div>
|
||||
</div>
|
||||
<div class="level-right">
|
||||
<div class="level-item">{{ $t("toolbar.download") }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
<hr class="dropdown-divider" />
|
||||
<a class="dropdown-item" @click="showSearch = true">
|
||||
<div class="level is-justify-content-start">
|
||||
<div class="level-left">
|
||||
<div class="level-item">
|
||||
<mdi:light-magnify />
|
||||
</div>
|
||||
</div>
|
||||
<div class="level-right is-justify-content-space-between is-flex-grow-1">
|
||||
<div class="level-item">{{ $t("toolbar.search") }}</div>
|
||||
<div class="level-item"><key-shortcut char="f"></key-shortcut></div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<hr class="dropdown-divider" />
|
||||
<a
|
||||
class="dropdown-item"
|
||||
@click="
|
||||
streamConfig.stdout = true;
|
||||
streamConfig.stderr = true;
|
||||
"
|
||||
>
|
||||
<div class="level is-justify-content-start">
|
||||
<div class="level-left">
|
||||
<div class="level-item">
|
||||
<div class="dropdown dropdown-end dropdown-hover">
|
||||
<label tabindex="0" class="btn btn-ghost btn-sm gap-0.5 px-2">
|
||||
<carbon:circle-solid class="w-2.5 text-red" v-if="streamConfig.stderr" />
|
||||
<carbon:circle-solid class="w-2.5 text-blue" v-if="streamConfig.stdout" />
|
||||
</label>
|
||||
<ul tabindex="0" class="menu dropdown-content rounded-box z-50 w-52 bg-base p-1 shadow">
|
||||
<li>
|
||||
<a @click.prevent="clear()">
|
||||
<octicon:trash-24 /> {{ $t("toolbar.clear") }}
|
||||
<key-shortcut char="k" :modifiers="['shift', 'meta']"></key-shortcut>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a :href="`${base}/api/logs/download/${container.host}/${container.id}`" download>
|
||||
<octicon:download-24 /> {{ $t("toolbar.download") }}
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a @click.prevent="showSearch = true">
|
||||
<mdi:light-magnify /> {{ $t("toolbar.search") }}
|
||||
<key-shortcut char="f"></key-shortcut>
|
||||
</a>
|
||||
</li>
|
||||
<li class="line"></li>
|
||||
<li>
|
||||
<a
|
||||
@click="
|
||||
streamConfig.stdout = true;
|
||||
streamConfig.stderr = true;
|
||||
"
|
||||
>
|
||||
<div class="flex h-4 w-4 gap-0.5">
|
||||
<template v-if="streamConfig.stderr && streamConfig.stdout">
|
||||
<carbon:circle-solid class="is-red is-small" />
|
||||
<carbon:circle-solid class="is-blue is-small" />
|
||||
<carbon:circle-solid class="w-2 text-red" />
|
||||
<carbon:circle-solid class="w-2 text-blue" />
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
<div class="level-right">
|
||||
{{ $t("toolbar.show-all") }}
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
<a
|
||||
class="dropdown-item"
|
||||
@click="
|
||||
streamConfig.stdout = true;
|
||||
streamConfig.stderr = false;
|
||||
"
|
||||
>
|
||||
<div class="level is-justify-content-start">
|
||||
<div class="level-left">
|
||||
<div class="level-item">
|
||||
<carbon:circle-solid class="is-blue is-small" v-if="!streamConfig.stderr && streamConfig.stdout" />
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
@click="
|
||||
streamConfig.stdout = true;
|
||||
streamConfig.stderr = false;
|
||||
"
|
||||
>
|
||||
<div class="flex h-4 w-4 flex-col gap-1">
|
||||
<carbon:circle-solid class="w-2 text-blue" v-if="!streamConfig.stderr && streamConfig.stdout" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="level-right">
|
||||
{{ $t("toolbar.show", { std: "STDOUT" }) }}
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
<a
|
||||
class="dropdown-item"
|
||||
@click="
|
||||
streamConfig.stdout = false;
|
||||
streamConfig.stderr = true;
|
||||
"
|
||||
>
|
||||
<div class="level is-justify-content-start">
|
||||
<div class="level-left">
|
||||
<div class="level-item">
|
||||
<carbon:circle-solid class="is-red is-small" v-if="streamConfig.stderr && !streamConfig.stdout" />
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
@click="
|
||||
streamConfig.stdout = false;
|
||||
streamConfig.stderr = true;
|
||||
"
|
||||
>
|
||||
<div class="flex h-4 w-4 flex-col gap-1">
|
||||
<carbon:circle-solid class="w-2 text-red" v-if="streamConfig.stderr && !streamConfig.stdout" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="level-right">
|
||||
<div class="level-item">
|
||||
{{ $t("toolbar.show", { std: "STDERR" }) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</dropdown-menu>
|
||||
{{ $t("toolbar.show", { std: "STDERR" }) }}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
@@ -124,14 +82,12 @@ const container = inject("container") as ComputedRef<Container>;
|
||||
const streamConfig = inject("stream-config") as { stdout: boolean; stderr: boolean };
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.level-left .level-item {
|
||||
width: 2.2em;
|
||||
align-items: center;
|
||||
margin-right: 0.5em;
|
||||
<style scoped lang="postcss">
|
||||
li.line {
|
||||
@apply h-px bg-base-content/20;
|
||||
}
|
||||
|
||||
.is-small {
|
||||
width: 0.6em;
|
||||
a {
|
||||
@apply whitespace-nowrap;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,20 +1,14 @@
|
||||
<template>
|
||||
<scrollable-view :scrollable="scrollable" v-if="container">
|
||||
<template #header v-if="showTitle">
|
||||
<div class="mr-0 columns is-mobile is-vcentered is-marginless has-boxshadow">
|
||||
<div class="column is-clipped is-paddingless">
|
||||
<container-title @close="$emit('close')" />
|
||||
</div>
|
||||
<div class="column is-narrow is-paddingless">
|
||||
<container-stat />
|
||||
</div>
|
||||
<div class="mx-2 flex items-center gap-2">
|
||||
<container-title @close="$emit('close')" />
|
||||
<container-stat class="ml-auto" />
|
||||
|
||||
<div class="mr-2 column is-narrow is-paddingless is-hidden-mobile">
|
||||
<log-actions-toolbar @clear="onClearClicked()" />
|
||||
</div>
|
||||
<div class="mr-2 column is-narrow is-paddingless" v-if="closable">
|
||||
<button class="delete is-medium" @click="close()"></button>
|
||||
</div>
|
||||
<log-actions-toolbar @clear="onClearClicked()" class="mobile-hidden" />
|
||||
<a class="btn btn-circle btn-xs" @click="close()" v-if="closable">
|
||||
<mdi:close />
|
||||
</a>
|
||||
</div>
|
||||
</template>
|
||||
<template #default="{ setLoading }">
|
||||
@@ -61,18 +55,3 @@ onKeyStroke("k", (e) => {
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
button.delete {
|
||||
background-color: var(--scheme-main-ter);
|
||||
opacity: 0.6;
|
||||
|
||||
&:after,
|
||||
&:before {
|
||||
background-color: var(--text-color);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,19 +1,10 @@
|
||||
<template>
|
||||
<date-time :date="date" class="date"></date-time>
|
||||
<tag size="small">
|
||||
<date-time :date="date" class="whitespace-nowrap text-[#258ccd]"></date-time>
|
||||
</tag>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
defineProps<{
|
||||
date: Date;
|
||||
}>();
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.date {
|
||||
padding-left: 5px;
|
||||
padding-right: 5px;
|
||||
border-radius: 3px;
|
||||
white-space: nowrap;
|
||||
background-color: var(--scheme-main-ter);
|
||||
color: #258ccd;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div :class="level" :data-position="position"></div>
|
||||
<div :data-level="level" :data-position="position" class="mt-1.5 h-2.5 w-2.5 flex-none rounded-lg"></div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { Position } from "@/models/LogEntry";
|
||||
@@ -10,54 +10,45 @@ defineProps<{
|
||||
}>();
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
div {
|
||||
display: inline-block;
|
||||
width: 0.7em;
|
||||
height: 0.7em;
|
||||
border-radius: 0.5em;
|
||||
align-self: auto;
|
||||
margin-top: 0.4em;
|
||||
<style lang="postcss" scoped>
|
||||
[data-position="start"] {
|
||||
border-radius: 0.5em 0.5em 0 0;
|
||||
height: 70%;
|
||||
margin-bottom: -0.4em;
|
||||
margin-top: auto;
|
||||
align-self: flex-end;
|
||||
}
|
||||
|
||||
&[data-position="start"] {
|
||||
border-radius: 0.5em 0.5em 0 0;
|
||||
height: 70%;
|
||||
margin-bottom: -0.2em;
|
||||
margin-top: auto;
|
||||
align-self: flex-end;
|
||||
}
|
||||
[data-position="middle"] {
|
||||
border-radius: 0;
|
||||
height: auto;
|
||||
margin: -0.4em 0;
|
||||
align-self: stretch;
|
||||
}
|
||||
|
||||
&[data-position="middle"] {
|
||||
border-radius: 0;
|
||||
height: auto;
|
||||
margin: -0.2em 0;
|
||||
align-self: auto;
|
||||
}
|
||||
[data-position="end"] {
|
||||
border-radius: 0 0 0.5em 0.5em;
|
||||
height: 70%;
|
||||
margin-top: -0.4em;
|
||||
align-self: flex-start;
|
||||
}
|
||||
|
||||
&[data-position="end"] {
|
||||
border-radius: 0 0 0.5em 0.5em;
|
||||
height: 70%;
|
||||
margin-top: -0.2em;
|
||||
align-self: flex-start;
|
||||
}
|
||||
[data-level="debug"],
|
||||
[data-level="trace"] {
|
||||
@apply bg-purple;
|
||||
}
|
||||
|
||||
&.debug,
|
||||
&.trace {
|
||||
background-color: var(--purple-color);
|
||||
}
|
||||
[data-level="info"] {
|
||||
@apply bg-green;
|
||||
}
|
||||
|
||||
&.info {
|
||||
background-color: var(--green-color);
|
||||
}
|
||||
[data-level="error"],
|
||||
[data-level="fatal"] {
|
||||
@apply bg-red;
|
||||
}
|
||||
|
||||
&.error,
|
||||
&.fatal {
|
||||
background-color: var(--red-color);
|
||||
}
|
||||
|
||||
&.warn,
|
||||
&.warning {
|
||||
background-color: var(--orange-color);
|
||||
}
|
||||
[data-level="warn"],
|
||||
[data-level="warning"] {
|
||||
@apply bg-orange;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -12,14 +12,12 @@ defineProps<{
|
||||
}>();
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.tag {
|
||||
&[std="stdout"] {
|
||||
color: var(--blue-color);
|
||||
}
|
||||
<style lang="postcss" scoped>
|
||||
[std="stdout"] {
|
||||
@apply text-blue;
|
||||
}
|
||||
|
||||
&[std="stderr"] {
|
||||
color: var(--red-color);
|
||||
}
|
||||
[std="stderr"] {
|
||||
@apply text-red;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,27 +1,21 @@
|
||||
<template>
|
||||
<ul class="events" :class="{ 'disable-wrap': !softWrap, [size]: true }">
|
||||
<ul class="events group py-4" :class="{ 'disable-wrap': !softWrap, [size]: true }">
|
||||
<li
|
||||
v-for="(item, index) in filtered"
|
||||
v-for="item in filtered"
|
||||
:key="item.id"
|
||||
:data-key="item.id"
|
||||
:class="{ selected: toRaw(item) === toRaw(lastSelectedItem) }"
|
||||
:class="{ 'border border-secondary': toRaw(item) === toRaw(lastSelectedItem) }"
|
||||
class="flex break-words px-4 py-1 last:snap-end odd:bg-base-lighter/30"
|
||||
>
|
||||
<div class="line-options" v-show="isSearching()">
|
||||
<dropdown-menu :class="{ 'is-last': index === filtered.length - 1 }" class="is-top minimal">
|
||||
<a class="dropdown-item" @click="handleJumpLineSelected($event, item)" :href="`#${item.id}`">
|
||||
<div class="level is-justify-content-start">
|
||||
<div class="level-left">
|
||||
<div class="level-item">
|
||||
<cil:find-in-page class="mr-4" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="level-right">
|
||||
<div class="level-item">Jump to Context</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</dropdown-menu>
|
||||
</div>
|
||||
<a
|
||||
class="btn btn-ghost tooltip-primary tooltip btn-sm tooltip-right mr-4 flex self-start font-sans font-normal normal-case text-secondary hover:text-secondary-focus"
|
||||
v-show="isSearching()"
|
||||
data-tip="Jump to Context"
|
||||
@click="handleJumpLineSelected($event, item)"
|
||||
:href="`#${item.id}`"
|
||||
>
|
||||
<ic:sharp-find-in-page />
|
||||
</a>
|
||||
<component :is="item.getComponent()" :log-entry="item" :visible-keys="visibleKeys.value"></component>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -64,9 +58,8 @@ watch(
|
||||
{ immediate: true, flush: "post" },
|
||||
);
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
<style scoped lang="postcss">
|
||||
.events {
|
||||
padding: 1em 0;
|
||||
font-family:
|
||||
ui-monospace,
|
||||
SFMono-Regular,
|
||||
@@ -77,41 +70,22 @@ watch(
|
||||
Menlo,
|
||||
monospace;
|
||||
|
||||
& > li {
|
||||
display: flex;
|
||||
word-wrap: break-word;
|
||||
padding: 0.2em 1em;
|
||||
|
||||
> li {
|
||||
&:last-child {
|
||||
scroll-snap-align: end;
|
||||
scroll-margin-block-end: 5rem;
|
||||
}
|
||||
|
||||
&:nth-child(odd) {
|
||||
background-color: rgba(125, 125, 125, 0.08);
|
||||
}
|
||||
|
||||
&.selected {
|
||||
border: 1px var(--secondary-color) solid;
|
||||
}
|
||||
|
||||
& > .line-options {
|
||||
display: flex;
|
||||
flex-direction: row-reverse;
|
||||
margin-right: 1em;
|
||||
}
|
||||
}
|
||||
|
||||
&.small {
|
||||
font-size: 60%;
|
||||
@apply text-[0.7em];
|
||||
}
|
||||
|
||||
&.medium {
|
||||
font-size: 80%;
|
||||
@apply text-[0.8em];
|
||||
}
|
||||
|
||||
&.large {
|
||||
font-size: 120%;
|
||||
@apply text-lg;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,15 +1,9 @@
|
||||
<template>
|
||||
<div class="columns is-1 is-variable is-mobile">
|
||||
<div class="column is-narrow" v-if="showStd">
|
||||
<log-std :std="logEntry.std"></log-std>
|
||||
</div>
|
||||
<div class="column is-narrow" v-if="showTimestamp">
|
||||
<log-date :date="logEntry.date"></log-date>
|
||||
</div>
|
||||
<div class="column is-narrow is-flex">
|
||||
<log-level :level="logEntry.level" :position="logEntry.position"></log-level>
|
||||
</div>
|
||||
<div class="text column" v-html="colorize(logEntry.message)"></div>
|
||||
<div class="flex items-start gap-x-2">
|
||||
<log-std :std="logEntry.std" v-if="showStd" />
|
||||
<log-date :date="logEntry.date" v-if="showTimestamp" />
|
||||
<log-level class="flex" :level="logEntry.level" :position="logEntry.position" />
|
||||
<div class="whitespace-pre-wrap group-[.disable-wrap]:whitespace-nowrap" v-html="colorize(logEntry.message)"></div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
@@ -24,15 +18,3 @@ defineProps<{
|
||||
const { markSearch } = useSearchFilter();
|
||||
const colorize = (value: string) => markSearch(ansiConvertor.toHtml(value));
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.disable-wrap {
|
||||
.text {
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
.text {
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
<template>
|
||||
<div class="is-flex-grow-1 has-text-centered my-4">
|
||||
<div class="is-relative">
|
||||
<zig-zag class="is-overlay mt-2"></zig-zag>
|
||||
<span class="text is-relative py-2 px-4">{{ $t("error.logs-skipped", { total: logEntry.totalSkipped }) }}</span>
|
||||
<div class="my-4 flex-1 text-center">
|
||||
<div class="relative">
|
||||
<zig-zag class="absolute inset-0 mt-2"></zig-zag>
|
||||
<span class="relative whitespace-pre-wrap bg-base px-4 py-2 font-bold">{{
|
||||
$t("error.logs-skipped", { total: logEntry.totalSkipped })
|
||||
}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -13,11 +15,3 @@ defineProps<{
|
||||
logEntry: SkippedLogsEntry;
|
||||
}>();
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.text {
|
||||
font-weight: bold;
|
||||
white-space: pre-wrap;
|
||||
background-color: var(--body-background-color);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
<template>
|
||||
<div class="has-text-centered is-relative host" @mouseenter="mouseOver = true" @mouseleave="mouseOver = false">
|
||||
<div class="has-border has-boxshadow is-hidden-mobile">
|
||||
<div class="relative hover:text-secondary" @mouseenter="mouseOver = true" @mouseleave="mouseOver = false">
|
||||
<div class="mobile-hidden flex overflow-hidden rounded-sm border border-primary px-px pb-px pt-1">
|
||||
<stat-sparkline :data="data" @selected-point="onSelectedPoint"></stat-sparkline>
|
||||
</div>
|
||||
<div class="has-background-body-color is-top-left">
|
||||
<span class="has-text-weight-light">{{ label }}</span>
|
||||
<span class="has-text-weight-bold">
|
||||
<div class="inline-flex gap-1 rounded bg-base p-px text-xs lg:absolute lg:-left-0.5 lg:-top-2">
|
||||
<div class="font-light uppercase">{{ label }}</div>
|
||||
<div class="select-none font-bold">
|
||||
{{ mouseOver ? selectedPoint?.value ?? selectedPoint?.y ?? statValue : statValue }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -23,30 +23,3 @@ function onSelectedPoint(point: Point<unknown>) {
|
||||
|
||||
let mouseOver = $ref(false);
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.has-border {
|
||||
border: 1px solid var(--primary-color);
|
||||
border-radius: 3px;
|
||||
padding: 1px 1px 0 1px;
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
padding-top: 0.25em;
|
||||
}
|
||||
|
||||
.has-background-body-color {
|
||||
background-color: var(--body-background-color);
|
||||
}
|
||||
|
||||
.host:hover span {
|
||||
color: var(--secondary-color);
|
||||
}
|
||||
|
||||
@media screen and (min-width: 768px) {
|
||||
.is-top-left {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0.75em;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<svg :width="width" :height="height" @mousemove="onMove">
|
||||
<path :d="path" class="area" />
|
||||
<line :x1="lineX" y1="0" :x2="lineX" :y2="height" class="line" />
|
||||
<svg :width="width" :height="height" @mousemove="onMove" class="group">
|
||||
<path :d="path" class="fill-primary" />
|
||||
<line :x1="lineX" y1="0" :x2="lineX" :y2="height" class="invisible stroke-secondary stroke-2 group-hover:visible" />
|
||||
</svg>
|
||||
</template>
|
||||
|
||||
@@ -42,19 +42,3 @@ function onMove(e: MouseEvent) {
|
||||
selectedPoint(point);
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
:deep(.area) {
|
||||
fill: var(--primary-color);
|
||||
}
|
||||
|
||||
:deep(.line) {
|
||||
stroke: var(--secondary-color);
|
||||
stroke-width: 2;
|
||||
display: none;
|
||||
}
|
||||
|
||||
svg:hover :deep(.line) {
|
||||
display: unset;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -2,18 +2,10 @@
|
||||
<svg width="100%" height="8" class="zigzag">
|
||||
<defs>
|
||||
<pattern id="zigzag" x="0" y="0" width="30" height="8" patternUnits="userSpaceOnUse">
|
||||
<line x1="0" y1="0" x2="15" y2="8" class="line" />
|
||||
<line x1="15" y1="8" x2="30" y2="0" class="line" />
|
||||
<line x1="0" y1="0" x2="15" y2="8" class="stroke-primary stroke-1" />
|
||||
<line x1="15" y1="8" x2="30" y2="0" class="stroke-primary stroke-1" />
|
||||
</pattern>
|
||||
</defs>
|
||||
<rect x="0" y="0" width="100%" height="100%" fill="url(#zigzag)"></rect>
|
||||
</svg>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.line {
|
||||
stroke: var(--primary-color);
|
||||
stroke-width: 1;
|
||||
stroke-linecap: round;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,237 +1,110 @@
|
||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||
|
||||
exports[`<LogEventSource /> > render html correctly > should render dates with 12 hour style 1`] = `
|
||||
"<ul data-v-2e92daca=\\"\\" class=\\"events medium\\">
|
||||
<li data-v-2e92daca=\\"\\" data-key=\\"1\\" class=\\"\\">
|
||||
<div data-v-2e92daca=\\"\\" class=\\"line-options\\" style=\\"display: none;\\">
|
||||
<div data-v-539164cb=\\"\\" data-v-2e92daca=\\"\\" class=\\"dropdown is-hoverable is-last is-top minimal\\">
|
||||
<div data-v-539164cb=\\"\\" class=\\"dropdown-trigger\\"><button data-v-539164cb=\\"\\" class=\\"button\\" aria-haspopup=\\"true\\" aria-controls=\\"dropdown-menu\\"><span data-v-539164cb=\\"\\" class=\\"icon\\"><svg data-v-539164cb=\\"\\" viewBox=\\"0 0 24 24\\" width=\\"1.2em\\" height=\\"1.2em\\"><path fill=\\"currentColor\\" d=\\"M12 16a2 2 0 0 1 2 2a2 2 0 0 1-2 2a2 2 0 0 1-2-2a2 2 0 0 1 2-2m0-6a2 2 0 0 1 2 2a2 2 0 0 1-2 2a2 2 0 0 1-2-2a2 2 0 0 1 2-2m0-6a2 2 0 0 1 2 2a2 2 0 0 1-2 2a2 2 0 0 1-2-2a2 2 0 0 1 2-2Z\\"></path></svg></span></button></div>
|
||||
<div data-v-539164cb=\\"\\" class=\\"dropdown-menu\\" id=\\"dropdown-menu\\" role=\\"menu\\">
|
||||
<div data-v-539164cb=\\"\\" class=\\"dropdown-content\\"><a data-v-2e92daca=\\"\\" class=\\"dropdown-item\\" href=\\"#1\\">
|
||||
<div data-v-2e92daca=\\"\\" class=\\"level is-justify-content-start\\">
|
||||
<div data-v-2e92daca=\\"\\" class=\\"level-left\\">
|
||||
<div data-v-2e92daca=\\"\\" class=\\"level-item\\"><svg data-v-2e92daca=\\"\\" viewBox=\\"0 0 512 512\\" width=\\"1.2em\\" height=\\"1.2em\\" class=\\"mr-4\\">
|
||||
<path fill=\\"currentColor\\" d=\\"M334.627 16H48v480h424V153.373ZM440 464H80V48h241.373L440 166.627Z\\"></path>
|
||||
<path fill=\\"currentColor\\" d=\\"M239.861 152a95.861 95.861 0 1 0 53.624 175.284l68.03 68.029l22.627-22.626l-67.5-67.5A95.816 95.816 0 0 0 239.861 152ZM176 247.861a63.862 63.862 0 1 1 63.861 63.861A63.933 63.933 0 0 1 176 247.861Z\\"></path>
|
||||
</svg></div>
|
||||
</div>
|
||||
<div data-v-2e92daca=\\"\\" class=\\"level-right\\">
|
||||
<div data-v-2e92daca=\\"\\" class=\\"level-item\\">Jump to Context</div>
|
||||
</div>
|
||||
</div>
|
||||
</a></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div data-v-a49e52d4=\\"\\" data-v-2e92daca=\\"\\" class=\\"columns is-1 is-variable is-mobile\\" visible-keys=\\"\\">
|
||||
"<ul data-v-2e92daca=\\"\\" class=\\"events group py-4 medium\\">
|
||||
<li data-v-2e92daca=\\"\\" data-key=\\"1\\" class=\\"flex break-words px-4 py-1 last:snap-end odd:bg-base-lighter/30\\"><a data-v-2e92daca=\\"\\" class=\\"btn btn-ghost tooltip-primary tooltip btn-sm tooltip-right mr-4 flex self-start font-sans font-normal normal-case text-secondary hover:text-secondary-focus\\" data-tip=\\"Jump to Context\\" href=\\"#1\\" style=\\"display: none;\\"><svg data-v-2e92daca=\\"\\" viewBox=\\"0 0 24 24\\" width=\\"1.2em\\" height=\\"1.2em\\">
|
||||
<path fill=\\"currentColor\\" d=\\"M20 19.59V8l-6-6H4v20l15.57-.02l-4.81-4.81c-.8.52-1.74.83-2.76.83c-2.76 0-5-2.24-5-5s2.24-5 5-5s5 2.24 5 5c0 1.02-.31 1.96-.83 2.75L20 19.59zM9 13c0 1.66 1.34 3 3 3s3-1.34 3-3s-1.34-3-3-3s-3 1.34-3 3z\\"></path>
|
||||
</svg></a>
|
||||
<div data-v-2e92daca=\\"\\" class=\\"flex items-start gap-x-2\\" visible-keys=\\"\\">
|
||||
<!--v-if-->
|
||||
<div data-v-a49e52d4=\\"\\" class=\\"column is-narrow\\">
|
||||
<div data-v-de513450=\\"\\" data-v-a49e52d4=\\"\\" class=\\"date\\"><time datetime=\\"2019-06-12T10:55:42.459Z\\" class=\\"is-hidden-mobile\\">06/12/2019</time> <time datetime=\\"2019-06-12T10:55:42.459Z\\">10:55:42 AM</time></div>
|
||||
<div data-v-961504e7=\\"\\" class=\\"inline-flex items-center justify-center rounded bg-base-lighter px-2 py-[0.2em] text-sm\\" size=\\"small\\">
|
||||
<div class=\\"whitespace-nowrap text-[#258ccd]\\"><time datetime=\\"2019-06-12T10:55:42.459Z\\" class=\\"mobile-hidden\\">06/12/2019</time><time datetime=\\"2019-06-12T10:55:42.459Z\\">10:55:42 AM</time></div>
|
||||
</div>
|
||||
<div data-v-a49e52d4=\\"\\" class=\\"column is-narrow is-flex\\">
|
||||
<div data-v-e625cddd=\\"\\" data-v-a49e52d4=\\"\\" class=\\"\\"></div>
|
||||
</div>
|
||||
<div data-v-a49e52d4=\\"\\" class=\\"text column\\"><test>foo bar</test></div>
|
||||
<div data-v-e625cddd=\\"\\" class=\\"mt-1.5 h-2.5 w-2.5 flex-none rounded-lg flex\\"></div>
|
||||
<div class=\\"whitespace-pre-wrap group-[.disable-wrap]:whitespace-nowrap\\"><test>foo bar</test></div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>"
|
||||
`;
|
||||
|
||||
exports[`<LogEventSource /> > render html correctly > should render dates with 24 hour style 1`] = `
|
||||
"<ul data-v-2e92daca=\\"\\" class=\\"events medium\\">
|
||||
<li data-v-2e92daca=\\"\\" data-key=\\"1\\" class=\\"\\">
|
||||
<div data-v-2e92daca=\\"\\" class=\\"line-options\\" style=\\"display: none;\\">
|
||||
<div data-v-539164cb=\\"\\" data-v-2e92daca=\\"\\" class=\\"dropdown is-hoverable is-last is-top minimal\\">
|
||||
<div data-v-539164cb=\\"\\" class=\\"dropdown-trigger\\"><button data-v-539164cb=\\"\\" class=\\"button\\" aria-haspopup=\\"true\\" aria-controls=\\"dropdown-menu\\"><span data-v-539164cb=\\"\\" class=\\"icon\\"><svg data-v-539164cb=\\"\\" viewBox=\\"0 0 24 24\\" width=\\"1.2em\\" height=\\"1.2em\\"><path fill=\\"currentColor\\" d=\\"M12 16a2 2 0 0 1 2 2a2 2 0 0 1-2 2a2 2 0 0 1-2-2a2 2 0 0 1 2-2m0-6a2 2 0 0 1 2 2a2 2 0 0 1-2 2a2 2 0 0 1-2-2a2 2 0 0 1 2-2m0-6a2 2 0 0 1 2 2a2 2 0 0 1-2 2a2 2 0 0 1-2-2a2 2 0 0 1 2-2Z\\"></path></svg></span></button></div>
|
||||
<div data-v-539164cb=\\"\\" class=\\"dropdown-menu\\" id=\\"dropdown-menu\\" role=\\"menu\\">
|
||||
<div data-v-539164cb=\\"\\" class=\\"dropdown-content\\"><a data-v-2e92daca=\\"\\" class=\\"dropdown-item\\" href=\\"#1\\">
|
||||
<div data-v-2e92daca=\\"\\" class=\\"level is-justify-content-start\\">
|
||||
<div data-v-2e92daca=\\"\\" class=\\"level-left\\">
|
||||
<div data-v-2e92daca=\\"\\" class=\\"level-item\\"><svg data-v-2e92daca=\\"\\" viewBox=\\"0 0 512 512\\" width=\\"1.2em\\" height=\\"1.2em\\" class=\\"mr-4\\">
|
||||
<path fill=\\"currentColor\\" d=\\"M334.627 16H48v480h424V153.373ZM440 464H80V48h241.373L440 166.627Z\\"></path>
|
||||
<path fill=\\"currentColor\\" d=\\"M239.861 152a95.861 95.861 0 1 0 53.624 175.284l68.03 68.029l22.627-22.626l-67.5-67.5A95.816 95.816 0 0 0 239.861 152ZM176 247.861a63.862 63.862 0 1 1 63.861 63.861A63.933 63.933 0 0 1 176 247.861Z\\"></path>
|
||||
</svg></div>
|
||||
</div>
|
||||
<div data-v-2e92daca=\\"\\" class=\\"level-right\\">
|
||||
<div data-v-2e92daca=\\"\\" class=\\"level-item\\">Jump to Context</div>
|
||||
</div>
|
||||
</div>
|
||||
</a></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div data-v-a49e52d4=\\"\\" data-v-2e92daca=\\"\\" class=\\"columns is-1 is-variable is-mobile\\" visible-keys=\\"\\">
|
||||
"<ul data-v-2e92daca=\\"\\" class=\\"events group py-4 medium\\">
|
||||
<li data-v-2e92daca=\\"\\" data-key=\\"1\\" class=\\"flex break-words px-4 py-1 last:snap-end odd:bg-base-lighter/30\\"><a data-v-2e92daca=\\"\\" class=\\"btn btn-ghost tooltip-primary tooltip btn-sm tooltip-right mr-4 flex self-start font-sans font-normal normal-case text-secondary hover:text-secondary-focus\\" data-tip=\\"Jump to Context\\" href=\\"#1\\" style=\\"display: none;\\"><svg data-v-2e92daca=\\"\\" viewBox=\\"0 0 24 24\\" width=\\"1.2em\\" height=\\"1.2em\\">
|
||||
<path fill=\\"currentColor\\" d=\\"M20 19.59V8l-6-6H4v20l15.57-.02l-4.81-4.81c-.8.52-1.74.83-2.76.83c-2.76 0-5-2.24-5-5s2.24-5 5-5s5 2.24 5 5c0 1.02-.31 1.96-.83 2.75L20 19.59zM9 13c0 1.66 1.34 3 3 3s3-1.34 3-3s-1.34-3-3-3s-3 1.34-3 3z\\"></path>
|
||||
</svg></a>
|
||||
<div data-v-2e92daca=\\"\\" class=\\"flex items-start gap-x-2\\" visible-keys=\\"\\">
|
||||
<!--v-if-->
|
||||
<div data-v-a49e52d4=\\"\\" class=\\"column is-narrow\\">
|
||||
<div data-v-de513450=\\"\\" data-v-a49e52d4=\\"\\" class=\\"date\\"><time datetime=\\"2019-06-12T10:55:42.459Z\\" class=\\"is-hidden-mobile\\">06/12/2019</time> <time datetime=\\"2019-06-12T10:55:42.459Z\\">10:55:42</time></div>
|
||||
<div data-v-961504e7=\\"\\" class=\\"inline-flex items-center justify-center rounded bg-base-lighter px-2 py-[0.2em] text-sm\\" size=\\"small\\">
|
||||
<div class=\\"whitespace-nowrap text-[#258ccd]\\"><time datetime=\\"2019-06-12T10:55:42.459Z\\" class=\\"mobile-hidden\\">06/12/2019</time><time datetime=\\"2019-06-12T10:55:42.459Z\\">10:55:42</time></div>
|
||||
</div>
|
||||
<div data-v-a49e52d4=\\"\\" class=\\"column is-narrow is-flex\\">
|
||||
<div data-v-e625cddd=\\"\\" data-v-a49e52d4=\\"\\" class=\\"\\"></div>
|
||||
</div>
|
||||
<div data-v-a49e52d4=\\"\\" class=\\"text column\\"><test>foo bar</test></div>
|
||||
<div data-v-e625cddd=\\"\\" class=\\"mt-1.5 h-2.5 w-2.5 flex-none rounded-lg flex\\"></div>
|
||||
<div class=\\"whitespace-pre-wrap group-[.disable-wrap]:whitespace-nowrap\\"><test>foo bar</test></div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>"
|
||||
`;
|
||||
|
||||
exports[`<LogEventSource /> > render html correctly > should render messages 1`] = `
|
||||
"<ul data-v-2e92daca=\\"\\" class=\\"events medium\\">
|
||||
<li data-v-2e92daca=\\"\\" data-key=\\"1\\" class=\\"\\">
|
||||
<div data-v-2e92daca=\\"\\" class=\\"line-options\\" style=\\"display: none;\\">
|
||||
<div data-v-539164cb=\\"\\" data-v-2e92daca=\\"\\" class=\\"dropdown is-hoverable is-last is-top minimal\\">
|
||||
<div data-v-539164cb=\\"\\" class=\\"dropdown-trigger\\"><button data-v-539164cb=\\"\\" class=\\"button\\" aria-haspopup=\\"true\\" aria-controls=\\"dropdown-menu\\"><span data-v-539164cb=\\"\\" class=\\"icon\\"><svg data-v-539164cb=\\"\\" viewBox=\\"0 0 24 24\\" width=\\"1.2em\\" height=\\"1.2em\\"><path fill=\\"currentColor\\" d=\\"M12 16a2 2 0 0 1 2 2a2 2 0 0 1-2 2a2 2 0 0 1-2-2a2 2 0 0 1 2-2m0-6a2 2 0 0 1 2 2a2 2 0 0 1-2 2a2 2 0 0 1-2-2a2 2 0 0 1 2-2m0-6a2 2 0 0 1 2 2a2 2 0 0 1-2 2a2 2 0 0 1-2-2a2 2 0 0 1 2-2Z\\"></path></svg></span></button></div>
|
||||
<div data-v-539164cb=\\"\\" class=\\"dropdown-menu\\" id=\\"dropdown-menu\\" role=\\"menu\\">
|
||||
<div data-v-539164cb=\\"\\" class=\\"dropdown-content\\"><a data-v-2e92daca=\\"\\" class=\\"dropdown-item\\" href=\\"#1\\">
|
||||
<div data-v-2e92daca=\\"\\" class=\\"level is-justify-content-start\\">
|
||||
<div data-v-2e92daca=\\"\\" class=\\"level-left\\">
|
||||
<div data-v-2e92daca=\\"\\" class=\\"level-item\\"><svg data-v-2e92daca=\\"\\" viewBox=\\"0 0 512 512\\" width=\\"1.2em\\" height=\\"1.2em\\" class=\\"mr-4\\">
|
||||
<path fill=\\"currentColor\\" d=\\"M334.627 16H48v480h424V153.373ZM440 464H80V48h241.373L440 166.627Z\\"></path>
|
||||
<path fill=\\"currentColor\\" d=\\"M239.861 152a95.861 95.861 0 1 0 53.624 175.284l68.03 68.029l22.627-22.626l-67.5-67.5A95.816 95.816 0 0 0 239.861 152ZM176 247.861a63.862 63.862 0 1 1 63.861 63.861A63.933 63.933 0 0 1 176 247.861Z\\"></path>
|
||||
</svg></div>
|
||||
</div>
|
||||
<div data-v-2e92daca=\\"\\" class=\\"level-right\\">
|
||||
<div data-v-2e92daca=\\"\\" class=\\"level-item\\">Jump to Context</div>
|
||||
</div>
|
||||
</div>
|
||||
</a></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div data-v-a49e52d4=\\"\\" data-v-2e92daca=\\"\\" class=\\"columns is-1 is-variable is-mobile\\" visible-keys=\\"\\">
|
||||
"<ul data-v-2e92daca=\\"\\" class=\\"events group py-4 medium\\">
|
||||
<li data-v-2e92daca=\\"\\" data-key=\\"1\\" class=\\"flex break-words px-4 py-1 last:snap-end odd:bg-base-lighter/30\\"><a data-v-2e92daca=\\"\\" class=\\"btn btn-ghost tooltip-primary tooltip btn-sm tooltip-right mr-4 flex self-start font-sans font-normal normal-case text-secondary hover:text-secondary-focus\\" data-tip=\\"Jump to Context\\" href=\\"#1\\" style=\\"display: none;\\"><svg data-v-2e92daca=\\"\\" viewBox=\\"0 0 24 24\\" width=\\"1.2em\\" height=\\"1.2em\\">
|
||||
<path fill=\\"currentColor\\" d=\\"M20 19.59V8l-6-6H4v20l15.57-.02l-4.81-4.81c-.8.52-1.74.83-2.76.83c-2.76 0-5-2.24-5-5s2.24-5 5-5s5 2.24 5 5c0 1.02-.31 1.96-.83 2.75L20 19.59zM9 13c0 1.66 1.34 3 3 3s3-1.34 3-3s-1.34-3-3-3s-3 1.34-3 3z\\"></path>
|
||||
</svg></a>
|
||||
<div data-v-2e92daca=\\"\\" class=\\"flex items-start gap-x-2\\" visible-keys=\\"\\">
|
||||
<!--v-if-->
|
||||
<div data-v-a49e52d4=\\"\\" class=\\"column is-narrow\\">
|
||||
<div data-v-de513450=\\"\\" data-v-a49e52d4=\\"\\" class=\\"date\\"><time datetime=\\"2019-06-12T10:55:42.459Z\\" class=\\"is-hidden-mobile\\">06/12/2019</time> <time datetime=\\"2019-06-12T10:55:42.459Z\\">10:55:42 AM</time></div>
|
||||
<div data-v-961504e7=\\"\\" class=\\"inline-flex items-center justify-center rounded bg-base-lighter px-2 py-[0.2em] text-sm\\" size=\\"small\\">
|
||||
<div class=\\"whitespace-nowrap text-[#258ccd]\\"><time datetime=\\"2019-06-12T10:55:42.459Z\\" class=\\"mobile-hidden\\">06/12/2019</time><time datetime=\\"2019-06-12T10:55:42.459Z\\">10:55:42 AM</time></div>
|
||||
</div>
|
||||
<div data-v-a49e52d4=\\"\\" class=\\"column is-narrow is-flex\\">
|
||||
<div data-v-e625cddd=\\"\\" data-v-a49e52d4=\\"\\" class=\\"\\"></div>
|
||||
</div>
|
||||
<div data-v-a49e52d4=\\"\\" class=\\"text column\\">This is a message.</div>
|
||||
<div data-v-e625cddd=\\"\\" class=\\"mt-1.5 h-2.5 w-2.5 flex-none rounded-lg flex\\"></div>
|
||||
<div class=\\"whitespace-pre-wrap group-[.disable-wrap]:whitespace-nowrap\\">This is a message.</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>"
|
||||
`;
|
||||
|
||||
exports[`<LogEventSource /> > render html correctly > should render messages with color 1`] = `
|
||||
"<ul data-v-2e92daca=\\"\\" class=\\"events medium\\">
|
||||
<li data-v-2e92daca=\\"\\" data-key=\\"1\\" class=\\"\\">
|
||||
<div data-v-2e92daca=\\"\\" class=\\"line-options\\" style=\\"display: none;\\">
|
||||
<div data-v-539164cb=\\"\\" data-v-2e92daca=\\"\\" class=\\"dropdown is-hoverable is-last is-top minimal\\">
|
||||
<div data-v-539164cb=\\"\\" class=\\"dropdown-trigger\\"><button data-v-539164cb=\\"\\" class=\\"button\\" aria-haspopup=\\"true\\" aria-controls=\\"dropdown-menu\\"><span data-v-539164cb=\\"\\" class=\\"icon\\"><svg data-v-539164cb=\\"\\" viewBox=\\"0 0 24 24\\" width=\\"1.2em\\" height=\\"1.2em\\"><path fill=\\"currentColor\\" d=\\"M12 16a2 2 0 0 1 2 2a2 2 0 0 1-2 2a2 2 0 0 1-2-2a2 2 0 0 1 2-2m0-6a2 2 0 0 1 2 2a2 2 0 0 1-2 2a2 2 0 0 1-2-2a2 2 0 0 1 2-2m0-6a2 2 0 0 1 2 2a2 2 0 0 1-2 2a2 2 0 0 1-2-2a2 2 0 0 1 2-2Z\\"></path></svg></span></button></div>
|
||||
<div data-v-539164cb=\\"\\" class=\\"dropdown-menu\\" id=\\"dropdown-menu\\" role=\\"menu\\">
|
||||
<div data-v-539164cb=\\"\\" class=\\"dropdown-content\\"><a data-v-2e92daca=\\"\\" class=\\"dropdown-item\\" href=\\"#1\\">
|
||||
<div data-v-2e92daca=\\"\\" class=\\"level is-justify-content-start\\">
|
||||
<div data-v-2e92daca=\\"\\" class=\\"level-left\\">
|
||||
<div data-v-2e92daca=\\"\\" class=\\"level-item\\"><svg data-v-2e92daca=\\"\\" viewBox=\\"0 0 512 512\\" width=\\"1.2em\\" height=\\"1.2em\\" class=\\"mr-4\\">
|
||||
<path fill=\\"currentColor\\" d=\\"M334.627 16H48v480h424V153.373ZM440 464H80V48h241.373L440 166.627Z\\"></path>
|
||||
<path fill=\\"currentColor\\" d=\\"M239.861 152a95.861 95.861 0 1 0 53.624 175.284l68.03 68.029l22.627-22.626l-67.5-67.5A95.816 95.816 0 0 0 239.861 152ZM176 247.861a63.862 63.862 0 1 1 63.861 63.861A63.933 63.933 0 0 1 176 247.861Z\\"></path>
|
||||
</svg></div>
|
||||
</div>
|
||||
<div data-v-2e92daca=\\"\\" class=\\"level-right\\">
|
||||
<div data-v-2e92daca=\\"\\" class=\\"level-item\\">Jump to Context</div>
|
||||
</div>
|
||||
</div>
|
||||
</a></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div data-v-a49e52d4=\\"\\" data-v-2e92daca=\\"\\" class=\\"columns is-1 is-variable is-mobile\\" visible-keys=\\"\\">
|
||||
"<ul data-v-2e92daca=\\"\\" class=\\"events group py-4 medium\\">
|
||||
<li data-v-2e92daca=\\"\\" data-key=\\"1\\" class=\\"flex break-words px-4 py-1 last:snap-end odd:bg-base-lighter/30\\"><a data-v-2e92daca=\\"\\" class=\\"btn btn-ghost tooltip-primary tooltip btn-sm tooltip-right mr-4 flex self-start font-sans font-normal normal-case text-secondary hover:text-secondary-focus\\" data-tip=\\"Jump to Context\\" href=\\"#1\\" style=\\"display: none;\\"><svg data-v-2e92daca=\\"\\" viewBox=\\"0 0 24 24\\" width=\\"1.2em\\" height=\\"1.2em\\">
|
||||
<path fill=\\"currentColor\\" d=\\"M20 19.59V8l-6-6H4v20l15.57-.02l-4.81-4.81c-.8.52-1.74.83-2.76.83c-2.76 0-5-2.24-5-5s2.24-5 5-5s5 2.24 5 5c0 1.02-.31 1.96-.83 2.75L20 19.59zM9 13c0 1.66 1.34 3 3 3s3-1.34 3-3s-1.34-3-3-3s-3 1.34-3 3z\\"></path>
|
||||
</svg></a>
|
||||
<div data-v-2e92daca=\\"\\" class=\\"flex items-start gap-x-2\\" visible-keys=\\"\\">
|
||||
<!--v-if-->
|
||||
<div data-v-a49e52d4=\\"\\" class=\\"column is-narrow\\">
|
||||
<div data-v-de513450=\\"\\" data-v-a49e52d4=\\"\\" class=\\"date\\"><time datetime=\\"2019-06-12T10:55:42.459Z\\" class=\\"is-hidden-mobile\\">06/12/2019</time> <time datetime=\\"2019-06-12T10:55:42.459Z\\">10:55:42 AM</time></div>
|
||||
<div data-v-961504e7=\\"\\" class=\\"inline-flex items-center justify-center rounded bg-base-lighter px-2 py-[0.2em] text-sm\\" size=\\"small\\">
|
||||
<div class=\\"whitespace-nowrap text-[#258ccd]\\"><time datetime=\\"2019-06-12T10:55:42.459Z\\" class=\\"mobile-hidden\\">06/12/2019</time><time datetime=\\"2019-06-12T10:55:42.459Z\\">10:55:42 AM</time></div>
|
||||
</div>
|
||||
<div data-v-a49e52d4=\\"\\" class=\\"column is-narrow is-flex\\">
|
||||
<div data-v-e625cddd=\\"\\" data-v-a49e52d4=\\"\\" class=\\"\\"></div>
|
||||
</div>
|
||||
<div data-v-a49e52d4=\\"\\" class=\\"text column\\"><span style=\\"color:#000\\">black<span style=\\"color:#AAA\\">white</span></span></div>
|
||||
<div data-v-e625cddd=\\"\\" class=\\"mt-1.5 h-2.5 w-2.5 flex-none rounded-lg flex\\"></div>
|
||||
<div class=\\"whitespace-pre-wrap group-[.disable-wrap]:whitespace-nowrap\\"><span style=\\"color:#000\\">black<span style=\\"color:#AAA\\">white</span></span></div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>"
|
||||
`;
|
||||
|
||||
exports[`<LogEventSource /> > render html correctly > should render messages with filter 1`] = `
|
||||
"<ul data-v-2e92daca=\\"\\" class=\\"events medium\\">
|
||||
<li data-v-2e92daca=\\"\\" data-key=\\"2\\" class=\\"\\">
|
||||
<div data-v-2e92daca=\\"\\" class=\\"line-options\\">
|
||||
<div data-v-539164cb=\\"\\" data-v-2e92daca=\\"\\" class=\\"dropdown is-hoverable is-last is-top minimal\\">
|
||||
<div data-v-539164cb=\\"\\" class=\\"dropdown-trigger\\"><button data-v-539164cb=\\"\\" class=\\"button\\" aria-haspopup=\\"true\\" aria-controls=\\"dropdown-menu\\"><span data-v-539164cb=\\"\\" class=\\"icon\\"><svg data-v-539164cb=\\"\\" viewBox=\\"0 0 24 24\\" width=\\"1.2em\\" height=\\"1.2em\\"><path fill=\\"currentColor\\" d=\\"M12 16a2 2 0 0 1 2 2a2 2 0 0 1-2 2a2 2 0 0 1-2-2a2 2 0 0 1 2-2m0-6a2 2 0 0 1 2 2a2 2 0 0 1-2 2a2 2 0 0 1-2-2a2 2 0 0 1 2-2m0-6a2 2 0 0 1 2 2a2 2 0 0 1-2 2a2 2 0 0 1-2-2a2 2 0 0 1 2-2Z\\"></path></svg></span></button></div>
|
||||
<div data-v-539164cb=\\"\\" class=\\"dropdown-menu\\" id=\\"dropdown-menu\\" role=\\"menu\\">
|
||||
<div data-v-539164cb=\\"\\" class=\\"dropdown-content\\"><a data-v-2e92daca=\\"\\" class=\\"dropdown-item\\" href=\\"#2\\">
|
||||
<div data-v-2e92daca=\\"\\" class=\\"level is-justify-content-start\\">
|
||||
<div data-v-2e92daca=\\"\\" class=\\"level-left\\">
|
||||
<div data-v-2e92daca=\\"\\" class=\\"level-item\\"><svg data-v-2e92daca=\\"\\" viewBox=\\"0 0 512 512\\" width=\\"1.2em\\" height=\\"1.2em\\" class=\\"mr-4\\">
|
||||
<path fill=\\"currentColor\\" d=\\"M334.627 16H48v480h424V153.373ZM440 464H80V48h241.373L440 166.627Z\\"></path>
|
||||
<path fill=\\"currentColor\\" d=\\"M239.861 152a95.861 95.861 0 1 0 53.624 175.284l68.03 68.029l22.627-22.626l-67.5-67.5A95.816 95.816 0 0 0 239.861 152ZM176 247.861a63.862 63.862 0 1 1 63.861 63.861A63.933 63.933 0 0 1 176 247.861Z\\"></path>
|
||||
</svg></div>
|
||||
</div>
|
||||
<div data-v-2e92daca=\\"\\" class=\\"level-right\\">
|
||||
<div data-v-2e92daca=\\"\\" class=\\"level-item\\">Jump to Context</div>
|
||||
</div>
|
||||
</div>
|
||||
</a></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div data-v-a49e52d4=\\"\\" data-v-2e92daca=\\"\\" class=\\"columns is-1 is-variable is-mobile\\" visible-keys=\\"\\">
|
||||
"<ul data-v-2e92daca=\\"\\" class=\\"events group py-4 medium\\">
|
||||
<li data-v-2e92daca=\\"\\" data-key=\\"2\\" class=\\"flex break-words px-4 py-1 last:snap-end odd:bg-base-lighter/30\\"><a data-v-2e92daca=\\"\\" class=\\"btn btn-ghost tooltip-primary tooltip btn-sm tooltip-right mr-4 flex self-start font-sans font-normal normal-case text-secondary hover:text-secondary-focus\\" data-tip=\\"Jump to Context\\" href=\\"#2\\"><svg data-v-2e92daca=\\"\\" viewBox=\\"0 0 24 24\\" width=\\"1.2em\\" height=\\"1.2em\\">
|
||||
<path fill=\\"currentColor\\" d=\\"M20 19.59V8l-6-6H4v20l15.57-.02l-4.81-4.81c-.8.52-1.74.83-2.76.83c-2.76 0-5-2.24-5-5s2.24-5 5-5s5 2.24 5 5c0 1.02-.31 1.96-.83 2.75L20 19.59zM9 13c0 1.66 1.34 3 3 3s3-1.34 3-3s-1.34-3-3-3s-3 1.34-3 3z\\"></path>
|
||||
</svg></a>
|
||||
<div data-v-2e92daca=\\"\\" class=\\"flex items-start gap-x-2\\" visible-keys=\\"\\">
|
||||
<!--v-if-->
|
||||
<div data-v-a49e52d4=\\"\\" class=\\"column is-narrow\\">
|
||||
<div data-v-de513450=\\"\\" data-v-a49e52d4=\\"\\" class=\\"date\\"><time datetime=\\"2019-06-12T10:55:42.459Z\\" class=\\"is-hidden-mobile\\">06/12/2019</time> <time datetime=\\"2019-06-12T10:55:42.459Z\\">10:55:42 AM</time></div>
|
||||
<div data-v-961504e7=\\"\\" class=\\"inline-flex items-center justify-center rounded bg-base-lighter px-2 py-[0.2em] text-sm\\" size=\\"small\\">
|
||||
<div class=\\"whitespace-nowrap text-[#258ccd]\\"><time datetime=\\"2019-06-12T10:55:42.459Z\\" class=\\"mobile-hidden\\">06/12/2019</time><time datetime=\\"2019-06-12T10:55:42.459Z\\">10:55:42 AM</time></div>
|
||||
</div>
|
||||
<div data-v-a49e52d4=\\"\\" class=\\"column is-narrow is-flex\\">
|
||||
<div data-v-e625cddd=\\"\\" data-v-a49e52d4=\\"\\" class=\\"\\"></div>
|
||||
</div>
|
||||
<div data-v-a49e52d4=\\"\\" class=\\"text column\\"><mark>test</mark> bar</div>
|
||||
<div data-v-e625cddd=\\"\\" class=\\"mt-1.5 h-2.5 w-2.5 flex-none rounded-lg flex\\"></div>
|
||||
<div class=\\"whitespace-pre-wrap group-[.disable-wrap]:whitespace-nowrap\\"><mark>test</mark> bar</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>"
|
||||
`;
|
||||
|
||||
exports[`<LogEventSource /> > render html correctly > should render messages with html entities 1`] = `
|
||||
"<ul data-v-2e92daca=\\"\\" class=\\"events medium\\">
|
||||
<li data-v-2e92daca=\\"\\" data-key=\\"1\\" class=\\"\\">
|
||||
<div data-v-2e92daca=\\"\\" class=\\"line-options\\" style=\\"display: none;\\">
|
||||
<div data-v-539164cb=\\"\\" data-v-2e92daca=\\"\\" class=\\"dropdown is-hoverable is-last is-top minimal\\">
|
||||
<div data-v-539164cb=\\"\\" class=\\"dropdown-trigger\\"><button data-v-539164cb=\\"\\" class=\\"button\\" aria-haspopup=\\"true\\" aria-controls=\\"dropdown-menu\\"><span data-v-539164cb=\\"\\" class=\\"icon\\"><svg data-v-539164cb=\\"\\" viewBox=\\"0 0 24 24\\" width=\\"1.2em\\" height=\\"1.2em\\"><path fill=\\"currentColor\\" d=\\"M12 16a2 2 0 0 1 2 2a2 2 0 0 1-2 2a2 2 0 0 1-2-2a2 2 0 0 1 2-2m0-6a2 2 0 0 1 2 2a2 2 0 0 1-2 2a2 2 0 0 1-2-2a2 2 0 0 1 2-2m0-6a2 2 0 0 1 2 2a2 2 0 0 1-2 2a2 2 0 0 1-2-2a2 2 0 0 1 2-2Z\\"></path></svg></span></button></div>
|
||||
<div data-v-539164cb=\\"\\" class=\\"dropdown-menu\\" id=\\"dropdown-menu\\" role=\\"menu\\">
|
||||
<div data-v-539164cb=\\"\\" class=\\"dropdown-content\\"><a data-v-2e92daca=\\"\\" class=\\"dropdown-item\\" href=\\"#1\\">
|
||||
<div data-v-2e92daca=\\"\\" class=\\"level is-justify-content-start\\">
|
||||
<div data-v-2e92daca=\\"\\" class=\\"level-left\\">
|
||||
<div data-v-2e92daca=\\"\\" class=\\"level-item\\"><svg data-v-2e92daca=\\"\\" viewBox=\\"0 0 512 512\\" width=\\"1.2em\\" height=\\"1.2em\\" class=\\"mr-4\\">
|
||||
<path fill=\\"currentColor\\" d=\\"M334.627 16H48v480h424V153.373ZM440 464H80V48h241.373L440 166.627Z\\"></path>
|
||||
<path fill=\\"currentColor\\" d=\\"M239.861 152a95.861 95.861 0 1 0 53.624 175.284l68.03 68.029l22.627-22.626l-67.5-67.5A95.816 95.816 0 0 0 239.861 152ZM176 247.861a63.862 63.862 0 1 1 63.861 63.861A63.933 63.933 0 0 1 176 247.861Z\\"></path>
|
||||
</svg></div>
|
||||
</div>
|
||||
<div data-v-2e92daca=\\"\\" class=\\"level-right\\">
|
||||
<div data-v-2e92daca=\\"\\" class=\\"level-item\\">Jump to Context</div>
|
||||
</div>
|
||||
</div>
|
||||
</a></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div data-v-a49e52d4=\\"\\" data-v-2e92daca=\\"\\" class=\\"columns is-1 is-variable is-mobile\\" visible-keys=\\"\\">
|
||||
"<ul data-v-2e92daca=\\"\\" class=\\"events group py-4 medium\\">
|
||||
<li data-v-2e92daca=\\"\\" data-key=\\"1\\" class=\\"flex break-words px-4 py-1 last:snap-end odd:bg-base-lighter/30\\"><a data-v-2e92daca=\\"\\" class=\\"btn btn-ghost tooltip-primary tooltip btn-sm tooltip-right mr-4 flex self-start font-sans font-normal normal-case text-secondary hover:text-secondary-focus\\" data-tip=\\"Jump to Context\\" href=\\"#1\\" style=\\"display: none;\\"><svg data-v-2e92daca=\\"\\" viewBox=\\"0 0 24 24\\" width=\\"1.2em\\" height=\\"1.2em\\">
|
||||
<path fill=\\"currentColor\\" d=\\"M20 19.59V8l-6-6H4v20l15.57-.02l-4.81-4.81c-.8.52-1.74.83-2.76.83c-2.76 0-5-2.24-5-5s2.24-5 5-5s5 2.24 5 5c0 1.02-.31 1.96-.83 2.75L20 19.59zM9 13c0 1.66 1.34 3 3 3s3-1.34 3-3s-1.34-3-3-3s-3 1.34-3 3z\\"></path>
|
||||
</svg></a>
|
||||
<div data-v-2e92daca=\\"\\" class=\\"flex items-start gap-x-2\\" visible-keys=\\"\\">
|
||||
<!--v-if-->
|
||||
<div data-v-a49e52d4=\\"\\" class=\\"column is-narrow\\">
|
||||
<div data-v-de513450=\\"\\" data-v-a49e52d4=\\"\\" class=\\"date\\"><time datetime=\\"2019-06-12T10:55:42.459Z\\" class=\\"is-hidden-mobile\\">06/12/2019</time> <time datetime=\\"2019-06-12T10:55:42.459Z\\">10:55:42 AM</time></div>
|
||||
<div data-v-961504e7=\\"\\" class=\\"inline-flex items-center justify-center rounded bg-base-lighter px-2 py-[0.2em] text-sm\\" size=\\"small\\">
|
||||
<div class=\\"whitespace-nowrap text-[#258ccd]\\"><time datetime=\\"2019-06-12T10:55:42.459Z\\" class=\\"mobile-hidden\\">06/12/2019</time><time datetime=\\"2019-06-12T10:55:42.459Z\\">10:55:42 AM</time></div>
|
||||
</div>
|
||||
<div data-v-a49e52d4=\\"\\" class=\\"column is-narrow is-flex\\">
|
||||
<div data-v-e625cddd=\\"\\" data-v-a49e52d4=\\"\\" class=\\"\\"></div>
|
||||
</div>
|
||||
<div data-v-a49e52d4=\\"\\" class=\\"text column\\"><test>foo bar</test></div>
|
||||
<div data-v-e625cddd=\\"\\" class=\\"mt-1.5 h-2.5 w-2.5 flex-none rounded-lg flex\\"></div>
|
||||
<div class=\\"whitespace-pre-wrap group-[.disable-wrap]:whitespace-nowrap\\"><test>foo bar</test></div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>"
|
||||
`;
|
||||
|
||||
exports[`<LogEventSource /> > renders correctly 1`] = `
|
||||
"<div data-v-1cd63c6e=\\"\\" class=\\"infinte-loader\\">
|
||||
<div data-v-1cd63c6e=\\"\\" class=\\"spinner\\" style=\\"display: none;\\">
|
||||
<div data-v-1cd63c6e=\\"\\" class=\\"bounce1\\"></div>
|
||||
<div data-v-1cd63c6e=\\"\\" class=\\"bounce2\\"></div>
|
||||
<div data-v-1cd63c6e=\\"\\" class=\\"bounce3\\"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ul data-v-2e92daca=\\"\\" class=\\"events medium\\"></ul>"
|
||||
"<div class=\\"flex min-h-[1px] justify-center\\"><span class=\\"loading loading-bars loading-md mt-4 text-primary\\" style=\\"display: none;\\"></span></div>
|
||||
<ul data-v-2e92daca=\\"\\" class=\\"events group py-4 medium\\"></ul>"
|
||||
`;
|
||||
|
||||
exports[`<LogEventSource /> > should parse messages 1`] = `
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
<template>
|
||||
<div @mouseenter="onMouseEnter" @mouseleave="onMouseLeave" ref="trigger"><slot></slot></div>
|
||||
<Teleport to="body">
|
||||
<Transition name="fade">
|
||||
<div v-show="show && (delayedShow || glopbalShow)" class="content" ref="content">
|
||||
<slot></slot>
|
||||
<teleport to="body">
|
||||
<transition name="fade">
|
||||
<div
|
||||
v-show="show && (delayedShow || glopbalShow)"
|
||||
class="fixed z-50 rounded border border-secondary/50 bg-base-lighter p-4 shadow"
|
||||
ref="content"
|
||||
>
|
||||
<slot name="content"></slot>
|
||||
</div>
|
||||
</Transition>
|
||||
</Teleport>
|
||||
</transition>
|
||||
</teleport>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
@@ -17,9 +21,8 @@ let show = ref(glopbalShow.value);
|
||||
let delayedShow = refDebounced(show, 1000);
|
||||
|
||||
let content: HTMLElement | null = $ref(null);
|
||||
let trigger: HTMLElement | null = $ref(null);
|
||||
|
||||
function onMouseEnter(e: MouseEvent) {
|
||||
const onMouseEnter = (e: Event) => {
|
||||
show.value = true;
|
||||
glopbalShow.value = true;
|
||||
if (e.target && content && e.target instanceof Element) {
|
||||
@@ -30,22 +33,26 @@ function onMouseEnter(e: MouseEvent) {
|
||||
content.style.left = `${x}px`;
|
||||
content.style.top = `${y}px`;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function onMouseLeave() {
|
||||
const onMouseLeave = () => {
|
||||
show.value = false;
|
||||
glopbalShow.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const el = useCurrentElement();
|
||||
useEventListener(() => el.value?.nextElementSibling, "mouseenter", onMouseEnter);
|
||||
useEventListener(() => el.value?.nextElementSibling, "mouseleave", onMouseLeave);
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.content {
|
||||
position: fixed;
|
||||
z-index: 9999;
|
||||
background: var(--scheme-main-ter);
|
||||
border-radius: 0.5em;
|
||||
padding: 1em;
|
||||
box-shadow: 0 0 0.5em rgba(0, 0, 0, 0.5);
|
||||
border: 1px solid var(--border-color);
|
||||
<style scoped lang="postcss">
|
||||
.fade-enter-active,
|
||||
.fade-leave-active {
|
||||
@apply transition-opacity;
|
||||
}
|
||||
|
||||
.fade-enter-from,
|
||||
.fade-leave-to {
|
||||
@apply opacity-0;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
<template>
|
||||
<transition name="fade">
|
||||
<div class="scroll-progress" ref="root" v-show="!autoHide || show">
|
||||
<transition name="fadeout">
|
||||
<div class="pointer-events-none relative inline-block" ref="root" v-show="!autoHide || show">
|
||||
<svg width="100" height="100" viewBox="0 0 100 100" :class="{ indeterminate }">
|
||||
<circle r="44" cx="50" cy="50" />
|
||||
<circle r="44" cx="50" cy="50" class="fill-base-darker stroke-primary" />
|
||||
</svg>
|
||||
<div class="is-overlay columns is-vcentered is-centered has-text-weight-light">
|
||||
<div class="absolute inset-0 flex items-center justify-center font-light">
|
||||
<template v-if="indeterminate">
|
||||
<div class="column is-narrow is-paddingless is-size-2">∞</div>
|
||||
<div class="text-4xl">∞</div>
|
||||
</template>
|
||||
<template v-else-if="!isNaN(scrollProgress)">
|
||||
<span class="column is-narrow is-paddingless is-size-2">
|
||||
<span class="text-4xl">
|
||||
{{ Math.ceil(scrollProgress * 100) }}
|
||||
</span>
|
||||
<span class="column is-narrow is-paddingless"> % </span>
|
||||
<span> % </span>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
@@ -54,36 +54,28 @@ watchPostEffect(() => {
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.scroll-progress {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
pointer-events: none;
|
||||
<style scoped lang="postcss">
|
||||
svg {
|
||||
filter: drop-shadow(0px 1px 1px rgba(0, 0, 0, 0.2));
|
||||
margin-top: 5px;
|
||||
&.indeterminate {
|
||||
animation: 2s linear infinite svg-animation;
|
||||
|
||||
svg {
|
||||
filter: drop-shadow(0px 1px 1px rgba(0, 0, 0, 0.2));
|
||||
margin-top: 5px;
|
||||
&.indeterminate {
|
||||
animation: 2s linear infinite svg-animation;
|
||||
|
||||
circle {
|
||||
animation: 1.4s ease-in-out infinite both circle-animation;
|
||||
}
|
||||
}
|
||||
circle {
|
||||
fill: var(--scheme-main-ter);
|
||||
fill-opacity: 0.8;
|
||||
transition: stroke-dashoffset 250ms ease-out;
|
||||
transform: rotate(-90deg);
|
||||
transform-origin: 50% 50%;
|
||||
stroke: var(--primary-color);
|
||||
stroke-dashoffset: calc(276.32px - v-bind(scrollProgress) * 276.32px);
|
||||
stroke-dasharray: 276.32px 276.32px;
|
||||
stroke-linecap: round;
|
||||
stroke-width: 3;
|
||||
will-change: stroke-dashoffset;
|
||||
animation: 1.4s ease-in-out infinite both circle-animation;
|
||||
}
|
||||
}
|
||||
circle {
|
||||
fill-opacity: 0.75;
|
||||
transition: stroke-dashoffset 250ms ease-out;
|
||||
transform: rotate(-90deg);
|
||||
transform-origin: 50% 50%;
|
||||
stroke-dashoffset: calc(276.32px - v-bind(scrollProgress) * 276.32px);
|
||||
stroke-dasharray: 276.32px 276.32px;
|
||||
stroke-linecap: round;
|
||||
stroke-width: 3;
|
||||
will-change: stroke-dashoffset;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes svg-animation {
|
||||
@@ -113,11 +105,11 @@ watchPostEffect(() => {
|
||||
}
|
||||
}
|
||||
|
||||
.fade-leave-active {
|
||||
transition: opacity 0.2s ease-in-out;
|
||||
.fadeout-leave-active {
|
||||
@apply transition-opacity;
|
||||
}
|
||||
|
||||
.fade-leave-to {
|
||||
.fadeout-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,24 +1,27 @@
|
||||
<template>
|
||||
<section :class="{ 'is-full-height-scrollable': scrollable }">
|
||||
<header v-if="$slots.header">
|
||||
<section :class="{ 'h-screen min-h-0': scrollable }" class="flex flex-col">
|
||||
<header
|
||||
v-if="$slots.header"
|
||||
class="sticky top-[70px] z-[2] border-b border-base-content/10 bg-base py-2 shadow-[1px_1px_2px_0_rgb(0,0,0,0.05)] md:top-0"
|
||||
>
|
||||
<slot name="header"></slot>
|
||||
</header>
|
||||
<main :data-scrolling="scrollable ? true : undefined">
|
||||
<div class="is-scrollbar-progress is-hidden-mobile" v-show="paused">
|
||||
<scroll-progress :indeterminate="loading" :auto-hide="!loading"></scroll-progress>
|
||||
<main :data-scrolling="scrollable ? true : undefined" class="snap-y overflow-auto">
|
||||
<div class="invisible mr-28 text-right md:visible" v-show="paused">
|
||||
<scroll-progress :indeterminate="loading" :auto-hide="!loading" class="z-2 !fixed top-16" />
|
||||
</div>
|
||||
<div ref="scrollableContent">
|
||||
<slot :setLoading="setLoading"></slot>
|
||||
</div>
|
||||
|
||||
<div ref="scrollObserver" class="is-scroll-observer"></div>
|
||||
<div ref="scrollObserver" class="h-px"></div>
|
||||
</main>
|
||||
|
||||
<div class="is-scrollbar-notification">
|
||||
<div class="mr-16 text-right">
|
||||
<transition name="fade">
|
||||
<button
|
||||
class="button has-boxshadow"
|
||||
:class="hasMore ? 'has-more' : ''"
|
||||
class="fixed bottom-8 rounded bg-primary p-3 text-primary-content shadow transition-colors hover:bg-primary-focus"
|
||||
:class="hasMore ? 'animate-bounce-fast bg-secondary text-secondary-content hover:bg-secondary-focus' : ''"
|
||||
@click="scrollToBottom()"
|
||||
v-show="paused"
|
||||
>
|
||||
@@ -71,106 +74,20 @@ function setLoading(value: boolean) {
|
||||
loading = value;
|
||||
}
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
<style scoped lang="postcss">
|
||||
.fade-enter-active,
|
||||
.fade-leave-active {
|
||||
@apply transition-opacity;
|
||||
}
|
||||
|
||||
header {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
background: var(--body-background-color);
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.05);
|
||||
z-index: 1;
|
||||
|
||||
@media screen and (max-width: 768px) {
|
||||
top: 70px;
|
||||
}
|
||||
}
|
||||
|
||||
&.is-full-height-scrollable {
|
||||
height: 100vh;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
main {
|
||||
flex: 1;
|
||||
overflow: auto;
|
||||
scroll-snap-type: y proximity;
|
||||
}
|
||||
|
||||
.is-scrollbar-progress {
|
||||
text-align: right;
|
||||
margin-right: 110px;
|
||||
|
||||
.scroll-progress {
|
||||
position: fixed;
|
||||
top: 60px;
|
||||
z-index: 2;
|
||||
}
|
||||
}
|
||||
|
||||
.is-scroll-observer {
|
||||
height: 1px;
|
||||
}
|
||||
|
||||
.is-scrollbar-notification {
|
||||
text-align: right;
|
||||
margin-right: 65px;
|
||||
|
||||
button {
|
||||
position: fixed;
|
||||
bottom: 30px;
|
||||
background-color: var(--primary-color);
|
||||
transition: background-color 0.24s ease-out;
|
||||
border: none !important;
|
||||
color: #eee;
|
||||
|
||||
&.has-more {
|
||||
background-color: var(--secondary-color);
|
||||
animation-name: bounce;
|
||||
animation-duration: 1000ms;
|
||||
animation-fill-mode: both;
|
||||
|
||||
color: #222;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes bounce {
|
||||
0%,
|
||||
20%,
|
||||
50%,
|
||||
80%,
|
||||
100% {
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
40% {
|
||||
transform: translateY(-30px);
|
||||
}
|
||||
|
||||
60% {
|
||||
transform: translateY(-15px);
|
||||
}
|
||||
}
|
||||
|
||||
.fade-enter-active,
|
||||
.fade-leave-active {
|
||||
transition: opacity 0.2s ease-out !important;
|
||||
}
|
||||
|
||||
.fade-enter,
|
||||
.fade-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
.fade-enter-from,
|
||||
.fade-leave-to {
|
||||
@apply opacity-0;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style>
|
||||
@media screen and (max-width: 768px) {
|
||||
.splitpanes__pane {
|
||||
overflow: unset !important;
|
||||
}
|
||||
.splitpanes__pane {
|
||||
overflow: unset !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,23 +1,22 @@
|
||||
<template>
|
||||
<div class="search columns is-gapless is-vcentered" v-show="showSearch" v-if="search">
|
||||
<div class="column">
|
||||
<p class="control has-icons-left">
|
||||
<input
|
||||
class="input"
|
||||
type="text"
|
||||
placeholder="Find / RegEx"
|
||||
ref="input"
|
||||
v-model="searchFilter"
|
||||
@keyup.esc="resetSearch()"
|
||||
/>
|
||||
<span class="icon is-left">
|
||||
<mdi:light-magnify />
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
<div class="column is-1 has-text-centered">
|
||||
<button class="delete is-medium" @click="resetSearch()"></button>
|
||||
<div
|
||||
class="fixed -right-px -top-px z-10 flex w-96 items-center gap-4 rounded-bl border border-secondary/20 bg-base-darker p-4 shadow"
|
||||
v-show="showSearch"
|
||||
v-if="search"
|
||||
>
|
||||
<div class="input input-primary flex h-auto items-center">
|
||||
<mdi:light-magnify />
|
||||
<input
|
||||
class="input flex-1"
|
||||
type="text"
|
||||
placeholder="Find / RegEx"
|
||||
ref="input"
|
||||
v-model="searchFilter"
|
||||
@keyup.esc="resetSearch()"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<a class="btn btn-circle btn-xs" @click="resetSearch()"> <mdi:close /></a>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -35,46 +34,3 @@ onKeyStroke("f", (e) => {
|
||||
|
||||
onUnmounted(() => resetSearch());
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.search {
|
||||
width: 350px;
|
||||
position: fixed;
|
||||
padding: 10px;
|
||||
background: var(--scheme-main-ter);
|
||||
top: 0;
|
||||
right: 0;
|
||||
border-radius: 0 0 0 5px;
|
||||
z-index: 10;
|
||||
box-shadow:
|
||||
0 1px 3px rgba(0, 0, 0, 0.12),
|
||||
0 1px 2px rgba(0, 0, 0, 0.24);
|
||||
|
||||
button.delete {
|
||||
margin-left: 1em;
|
||||
background-color: var(--scheme-main-ter);
|
||||
opacity: 0.6;
|
||||
|
||||
&:after,
|
||||
&:before {
|
||||
background-color: var(--text-color);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.icon {
|
||||
padding: 10px 3px;
|
||||
}
|
||||
|
||||
.input {
|
||||
color: var(--body-color);
|
||||
|
||||
&::placeholder {
|
||||
color: var(--border-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,50 +1,51 @@
|
||||
<template>
|
||||
<div v-if="ready">
|
||||
<nav class="breadcrumb menu-label" aria-label="breadcrumbs">
|
||||
<ul v-if="sessionHost">
|
||||
<li>
|
||||
<a href="#" @click.prevent="setHost(null)">{{ hosts[sessionHost].name }}</a>
|
||||
<div v-if="ready" data-testid="side-menu">
|
||||
<div class="breadcrumbs text-sm">
|
||||
<ul>
|
||||
<li><a @click.prevent="setHost(null)">Hosts</a></li>
|
||||
<li v-if="sessionHost && hosts[sessionHost]">
|
||||
{{ hosts[sessionHost].name }}
|
||||
</li>
|
||||
</ul>
|
||||
<ul v-else>
|
||||
<li>Hosts</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
<transition :name="sessionHost ? 'slide-left' : 'slide-right'" mode="out-in">
|
||||
<ul class="menu-list" v-if="!sessionHost">
|
||||
<ul class="menu p-0" v-if="!sessionHost">
|
||||
<li v-for="host in config.hosts">
|
||||
<a @click.prevent="setHost(host.id)">{{ host.name }}</a>
|
||||
<a @click.prevent="setHost(host.id)">
|
||||
<ph:computer-tower />
|
||||
{{ host.name }}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<transition-group tag="ul" name="list" class="menu-list" v-else>
|
||||
<li v-for="item in menuItems" :key="item.id" :class="item.state" :data-label="item.id">
|
||||
<div class="menu-label mt-4 mb-3" v-if="isLabel(item)">
|
||||
<transition-group tag="ul" name="list" class="containers menu p-0 [&_li.menu-title]:px-0" v-else>
|
||||
<li
|
||||
v-for="item in menuItems"
|
||||
:key="item.id"
|
||||
:class="isLabel(item) ? 'menu-title' : item.state"
|
||||
:data-testid="item.id"
|
||||
>
|
||||
<template v-if="isLabel(item)">
|
||||
{{ item.label }}
|
||||
</div>
|
||||
</template>
|
||||
<popup v-else>
|
||||
<router-link
|
||||
:to="{ name: 'container-id', params: { id: item.id } }"
|
||||
active-class="is-active"
|
||||
active-class="active-primary"
|
||||
:title="item.name"
|
||||
>
|
||||
<div class="container is-flex is-align-items-center">
|
||||
<div class="is-flex-grow-1 is-ellipsis">
|
||||
<span>{{ item.name }}</span
|
||||
><span class="has-text-weight-light has-light-opacity" v-if="item.isSwarm">{{ item.swarmId }}</span>
|
||||
</div>
|
||||
<div class="is-flex-shrink-1 is-flex icons">
|
||||
<div
|
||||
class="icon is-small pin"
|
||||
@click.stop.prevent="store.appendActiveContainer(item)"
|
||||
v-show="!activeContainersById[item.id]"
|
||||
:title="$t('tooltip.pin-column')"
|
||||
>
|
||||
<cil:columns />
|
||||
</div>
|
||||
|
||||
<container-health :health="item.health"></container-health>
|
||||
</div>
|
||||
<div class="truncate">
|
||||
{{ item.name }}<span class="font-light opacity-70" v-if="item.isSwarm">{{ item.swarmId }}</span>
|
||||
</div>
|
||||
<span
|
||||
class="pin"
|
||||
@click.stop.prevent="store.appendActiveContainer(item)"
|
||||
v-show="!activeContainersById[item.id]"
|
||||
:title="$t('tooltip.pin-column')"
|
||||
>
|
||||
<cil:columns />
|
||||
</span>
|
||||
|
||||
<container-health :health="item.health"></container-health>
|
||||
</router-link>
|
||||
<template #content>
|
||||
<container-popup :container="item"></container-popup>
|
||||
@@ -54,9 +55,10 @@
|
||||
</transition-group>
|
||||
</transition>
|
||||
</div>
|
||||
<ul class="menu-list is-hidden-mobile has-light-opacity" v-else>
|
||||
<li v-for="index in 7" class="my-4"><o-skeleton animated size="large" :key="index"></o-skeleton></li>
|
||||
</ul>
|
||||
<div role="status" class="flex animate-pulse flex-col gap-4" v-else>
|
||||
<div class="h-3 w-full rounded-full bg-base-content/50 opacity-50" v-for="_ in 9"></div>
|
||||
<span class="sr-only">Loading...</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
@@ -104,7 +106,7 @@ const groupedContainers = computed(() =>
|
||||
|
||||
type MenuLabel = { label: string; id: string; state: string };
|
||||
const pinnedLabel = { label: t("label.pinned"), id: "pinned", state: "label" } as MenuLabel;
|
||||
const allLabel = { label: t("label.containers"), id: "all", state: "label" } as MenuLabel;
|
||||
const allLabel = { label: t("label.containers"), id: "containers", state: "label" } as MenuLabel;
|
||||
|
||||
function isLabel(item: Container | MenuLabel): item is MenuLabel {
|
||||
return (item as MenuLabel).label !== undefined;
|
||||
@@ -138,35 +140,26 @@ const activeContainersById = computed(() =>
|
||||
),
|
||||
);
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.has-light-opacity {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
li.exited a,
|
||||
li.dead a {
|
||||
color: #777;
|
||||
}
|
||||
|
||||
.icons {
|
||||
column-gap: 0.35em;
|
||||
align-items: baseline;
|
||||
}
|
||||
a {
|
||||
<style scoped lang="postcss">
|
||||
.containers a {
|
||||
@apply auto-cols-[auto_max-content];
|
||||
.pin {
|
||||
display: none;
|
||||
|
||||
&:hover {
|
||||
color: var(--secondary-color);
|
||||
@apply text-secondary;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.pin {
|
||||
display: block;
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
}
|
||||
li.exited {
|
||||
@apply opacity-50;
|
||||
}
|
||||
|
||||
.slide-left-enter-active,
|
||||
.slide-left-leave-active,
|
||||
@@ -177,22 +170,22 @@ a {
|
||||
|
||||
.slide-left-enter-from {
|
||||
opacity: 0;
|
||||
transform: translateX(100%);
|
||||
transform: translateX(20px);
|
||||
}
|
||||
|
||||
.slide-right-enter-from {
|
||||
opacity: 0;
|
||||
transform: translateX(-100%);
|
||||
transform: translateX(-20px);
|
||||
}
|
||||
|
||||
.slide-left-leave-to {
|
||||
opacity: 0;
|
||||
transform: translateX(-100%);
|
||||
transform: translateX(-20px);
|
||||
}
|
||||
|
||||
.slide-right-leave-to {
|
||||
opacity: 0;
|
||||
transform: translateX(100%);
|
||||
transform: translateX(20px);
|
||||
}
|
||||
|
||||
.list-move,
|
||||
|
||||
@@ -1,48 +1,40 @@
|
||||
<template>
|
||||
<aside>
|
||||
<div class="columns is-marginless">
|
||||
<div class="column is-paddingless">
|
||||
<h1>
|
||||
<router-link :to="{ name: 'index' }">
|
||||
<svg class="logo">
|
||||
<use href="#logo"></use>
|
||||
</svg>
|
||||
</router-link>
|
||||
<aside class="fixed h-screen w-[inherit] overflow-auto p-4" data-testid="navigation">
|
||||
<h1>
|
||||
<router-link :to="{ name: 'index' }">
|
||||
<svg class="h-14 w-28 fill-secondary">
|
||||
<use href="#logo"></use>
|
||||
</svg>
|
||||
</router-link>
|
||||
|
||||
<small class="subtitle is-6 is-block mb-4" v-if="hostname">
|
||||
{{ hostname }}
|
||||
</small>
|
||||
</h1>
|
||||
</div>
|
||||
</div>
|
||||
<div class="columns is-marginless">
|
||||
<div class="column is-narrow py-0 pl-0 pr-1">
|
||||
<button class="button is-rounded is-small" @click="$emit('search')" :title="$t('tooltip.search')">
|
||||
<span class="icon">
|
||||
<mdi:light-magnify />
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="column is-narrow py-0" :class="secured ? 'pl-0 pr-1' : 'px-0'">
|
||||
<router-link
|
||||
:to="{ name: 'settings' }"
|
||||
active-class="is-active"
|
||||
class="button is-rounded is-small"
|
||||
:aria-label="$t('title.settings')"
|
||||
>
|
||||
<span class="icon">
|
||||
<mdi:light-cog />
|
||||
</span>
|
||||
</router-link>
|
||||
</div>
|
||||
<div class="column is-narrow py-0 px-0" v-if="secured">
|
||||
<a class="button is-rounded is-small" :href="`${base}/logout`" :title="$t('button.logout')">
|
||||
<span class="icon">
|
||||
<mdi:light-logout />
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
<small class="mb-4 block text-xs font-light" v-if="hostname">
|
||||
{{ hostname }}
|
||||
</small>
|
||||
</h1>
|
||||
|
||||
<div class="mt-4 flex gap-4">
|
||||
<router-link
|
||||
:to="{ name: 'settings' }"
|
||||
:aria-label="$t('title.settings')"
|
||||
data-testid="settings"
|
||||
class="btn btn-circle btn-sm"
|
||||
>
|
||||
<mdi:light-cog />
|
||||
</router-link>
|
||||
<a :href="`${base}/logout`" :title="$t('button.logout')" v-if="secured" class="btn btn-circle btn-sm">
|
||||
<mdi:light-logout />
|
||||
</a>
|
||||
</div>
|
||||
<a
|
||||
class="input input-sm mt-4 inline-flex cursor-pointer items-center gap-2 font-light hover:border-primary"
|
||||
@click="$emit('search')"
|
||||
:title="$t('tooltip.search')"
|
||||
>
|
||||
<mdi:light-magnify />
|
||||
Search
|
||||
<key-shortcut char="k"></key-shortcut>
|
||||
</a>
|
||||
|
||||
<side-menu class="mt-4"></side-menu>
|
||||
</aside>
|
||||
</template>
|
||||
@@ -50,22 +42,3 @@
|
||||
<script lang="ts" setup>
|
||||
const { base, secured, hostname } = config;
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
aside {
|
||||
padding: 1em;
|
||||
height: 100vh;
|
||||
overflow: auto;
|
||||
position: fixed;
|
||||
width: inherit;
|
||||
|
||||
.is-hidden-mobile.is-active {
|
||||
display: block !important;
|
||||
}
|
||||
}
|
||||
|
||||
.logo {
|
||||
width: 122px;
|
||||
height: 54px;
|
||||
fill: var(--logo-color);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div>
|
||||
<time :datetime="date.toISOString()" class="is-hidden-mobile">{{ dateStr }}</time>
|
||||
<time :datetime="date.toISOString()" class="mobile-hidden">{{ dateStr }}</time>
|
||||
<time :datetime="date.toISOString()">{{ timeStr }}</time>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
44
assets/components/common/Dropdown.vue
Normal file
@@ -0,0 +1,44 @@
|
||||
<template>
|
||||
<details class="dropdown" ref="details" v-on-click-outside="close">
|
||||
<summary class="btn btn-primary flex-nowrap font-normal" v-bind="$attrs">
|
||||
<slot name="trigger"> {{ values[modelValue] ?? defaultLabel }} <carbon:caret-down /></slot>
|
||||
</summary>
|
||||
<ul class="menu dropdown-content rounded-box z-50 w-52 bg-base p-2 shadow">
|
||||
<slot>
|
||||
<li v-for="item in options">
|
||||
<a @click="modelValue = item.value">
|
||||
<mdi-light:check class="w-4" v-if="modelValue == item.value" />
|
||||
<div v-else class="w-4"></div>
|
||||
{{ item.label }}
|
||||
</a>
|
||||
</li>
|
||||
</slot>
|
||||
</ul>
|
||||
</details>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { vOnClickOutside } from "@vueuse/components";
|
||||
type DropdownItem = {
|
||||
label: string;
|
||||
value: string;
|
||||
};
|
||||
const { options = [], defaultLabel = "" } = defineProps<{ options?: DropdownItem[]; defaultLabel?: string }>();
|
||||
const { modelValue } = defineModels<{
|
||||
modelValue: string;
|
||||
}>();
|
||||
|
||||
const values = computed(() =>
|
||||
options.reduce(
|
||||
(acc, curr) => {
|
||||
acc[curr.value] = curr.label;
|
||||
return acc;
|
||||
},
|
||||
{} as Record<string, string>,
|
||||
),
|
||||
);
|
||||
|
||||
const details = ref<HTMLElement | null>(null);
|
||||
const close = () => details.value?.removeAttribute("open");
|
||||
watch(modelValue, () => close());
|
||||
</script>
|
||||
19
assets/components/common/KeyShortcut.vue
Normal file
@@ -0,0 +1,19 @@
|
||||
<template>
|
||||
<div class="inline-flex items-center">
|
||||
<template v-if="modifiers.includes('shift')">
|
||||
<carbon:mac-shift />
|
||||
</template>
|
||||
<template v-if="modifiers.includes('meta')">
|
||||
<ph:command v-if="isMac" class="h-4 w-4" />
|
||||
<ph:control-bold v-else class="h-4 w-4" />
|
||||
</template>
|
||||
<kbd class="uppercase">{{ char }}</kbd>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
const isMac = /(Mac|iPhone|iPod|iPad)/i.test(navigator.userAgent);
|
||||
</script>
|
||||
<script lang="ts" setup>
|
||||
const { modifiers = ["meta"], char } = defineProps<{ char: string; modifiers?: ("^" | "meta" | "shift")[] }>();
|
||||
</script>
|
||||
@@ -1,88 +1,58 @@
|
||||
<template>
|
||||
<aside>
|
||||
<div class="columns is-marginless is-gapless is-mobile is-vcentered">
|
||||
<div class="column is-narrow">
|
||||
<router-link :to="{ name: 'index' }">
|
||||
<svg class="logo">
|
||||
<use href="#logo"></use>
|
||||
</svg>
|
||||
</router-link>
|
||||
</div>
|
||||
<nav class="fixed top-0 z-10 w-full border-b border-base-content/20 bg-base p-2" data-testid="navigation">
|
||||
<div class="flex items-center">
|
||||
<router-link :to="{ name: 'index' }">
|
||||
<svg class="h-14 w-28 fill-secondary">
|
||||
<use href="#logo"></use>
|
||||
</svg>
|
||||
</router-link>
|
||||
|
||||
<div class="column is-narrow push-right">
|
||||
<a
|
||||
role="button"
|
||||
class="navbar-burger burger is-hidden-tablet is-pulled-right"
|
||||
@click="showNav = !showNav"
|
||||
:class="{ 'is-active': showNav }"
|
||||
>
|
||||
<span></span> <span></span> <span></span>
|
||||
<div class="ml-auto flex items-center gap-2">
|
||||
<a class="btn btn-circle flex" @click="$emit('search')" :title="$t('tooltip.search')">
|
||||
<mdi:light-magnify class="h-5 w-5" />
|
||||
</a>
|
||||
<label class="btn btn-circle swap swap-rotate" data-testid="hamburger">
|
||||
<input type="checkbox" v-model="show" />
|
||||
<mdi:close class="swap-on" />
|
||||
<mdi:hamburger-menu class="swap-off" />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="menu-label level is-mobile is-hidden-mobile" :class="{ 'is-active': showNav }">
|
||||
<div v-if="config.hosts.length > 1">
|
||||
<o-dropdown v-model="sessionHost" aria-role="list">
|
||||
<template #trigger>
|
||||
<o-button variant="primary" type="button" size="small">
|
||||
<span>{{ sessionHost ? hosts[sessionHost].name : "" }}</span>
|
||||
<span class="icon">
|
||||
<carbon:caret-down />
|
||||
</span>
|
||||
</o-button>
|
||||
</template>
|
||||
|
||||
<o-dropdown-item :value="value.id" aria-role="listitem" v-for="value in config.hosts" :key="value">
|
||||
<span>{{ value.name }}</span>
|
||||
</o-dropdown-item>
|
||||
</o-dropdown>
|
||||
</div>
|
||||
|
||||
<div class="level-item has-text-centered">
|
||||
<div>
|
||||
<button class="button is-small is-rounded" @click="$emit('search')" :title="$t('tooltip.search')">
|
||||
<span class="icon">
|
||||
<mdi:light-magnify />
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="level-item has-text-centered">
|
||||
<div>
|
||||
<router-link :to="{ name: 'settings' }" active-class="is-active" class="button is-small is-rounded">
|
||||
<span class="icon">
|
||||
<mdi:light-cog />
|
||||
</span>
|
||||
<transition name="fade">
|
||||
<div v-show="show">
|
||||
<div class="mt-4 flex items-center justify-center gap-2">
|
||||
<dropdown
|
||||
v-model="sessionHost"
|
||||
:options="hosts"
|
||||
defaultLabel="Hosts"
|
||||
class="btn-sm"
|
||||
v-if="config.hosts.length > 1"
|
||||
/>
|
||||
<router-link :to="{ name: 'settings' }" class="btn btn-outline btn-sm">
|
||||
<mdi:light-cog /> {{ $t("button.settings") }}
|
||||
</router-link>
|
||||
</div>
|
||||
</div>
|
||||
<div class="level-item has-text-centered" v-if="secured">
|
||||
<div>
|
||||
<a class="button is-small is-rounded" :href="`${base}/logout`" :title="$t('button.logout')">
|
||||
<span class="icon">
|
||||
<mdi:light-logout />
|
||||
</span>
|
||||
<a class="btn btn-outline btn-sm" :href="`${base}/logout`" :title="$t('button.logout')" v-if="secured">
|
||||
<mdi:light-logout /> {{ $t("button.logout") }}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="menu-label is-hidden-mobile" :class="{ 'is-active': showNav }">{{ $t("label.containers") }}</p>
|
||||
<ul class="menu-list is-hidden-mobile" :class="{ 'is-active': showNav }">
|
||||
<li v-for="item in sortedContainers" :key="item.id">
|
||||
<router-link
|
||||
:to="{ name: 'container-id', params: { id: item.id } }"
|
||||
active-class="is-active"
|
||||
:title="item.name"
|
||||
>
|
||||
<div class="is-ellipsis">
|
||||
{{ item.name }}
|
||||
</div>
|
||||
</router-link>
|
||||
</li>
|
||||
</ul>
|
||||
</aside>
|
||||
<ul class="menu">
|
||||
<li class="menu-title">{{ $t("label.containers") }}</li>
|
||||
<li v-for="item in sortedContainers" :key="item.id">
|
||||
<router-link
|
||||
:to="{ name: 'container-id', params: { id: item.id } }"
|
||||
active-class="active-primary"
|
||||
class="truncate"
|
||||
:title="item.name"
|
||||
>
|
||||
{{ item.name }}
|
||||
</router-link>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</transition>
|
||||
</nav>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
@@ -92,10 +62,10 @@ const store = useContainerStore();
|
||||
const route = useRoute();
|
||||
const { visibleContainers } = storeToRefs(store);
|
||||
|
||||
let showNav = $ref(false);
|
||||
const show = ref(false);
|
||||
|
||||
watch(route, () => {
|
||||
showNav = false;
|
||||
show.value = false;
|
||||
});
|
||||
|
||||
const sortedContainers = computed(() =>
|
||||
@@ -112,59 +82,26 @@ const sortedContainers = computed(() =>
|
||||
}),
|
||||
);
|
||||
|
||||
const hosts = computed(() =>
|
||||
config.hosts.reduce(
|
||||
(acc, item) => {
|
||||
acc[item.id] = item;
|
||||
return acc;
|
||||
},
|
||||
{} as Record<string, { name: string; id: string }>,
|
||||
),
|
||||
);
|
||||
const hosts = computed(() => config.hosts.map(({ id, name }) => ({ value: id, label: name })));
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
aside {
|
||||
padding: 1em;
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: var(--scheme-main-ter);
|
||||
z-index: 10;
|
||||
max-height: 100vh;
|
||||
overflow: auto;
|
||||
<style scoped lang="postcss">
|
||||
.fade-enter-active,
|
||||
.fade-leave-active {
|
||||
@apply transition-opacity;
|
||||
}
|
||||
|
||||
.level.is-hidden-mobile.is-active {
|
||||
display: flex !important;
|
||||
}
|
||||
.fade-enter-active .menu,
|
||||
.fade-leave-active .menu {
|
||||
@apply transition-transform;
|
||||
}
|
||||
|
||||
.menu-label {
|
||||
margin-top: 1em;
|
||||
}
|
||||
.fade-enter-from,
|
||||
.fade-leave-to {
|
||||
@apply opacity-0;
|
||||
}
|
||||
|
||||
.title {
|
||||
text-shadow: 0px 1px 1px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.burger {
|
||||
color: var(--body-color);
|
||||
}
|
||||
|
||||
.is-hidden-mobile.is-active {
|
||||
display: block !important;
|
||||
}
|
||||
|
||||
.navbar-burger {
|
||||
height: 2.35rem;
|
||||
}
|
||||
|
||||
.logo {
|
||||
width: 82px;
|
||||
height: 36px;
|
||||
fill: var(--logo-color);
|
||||
}
|
||||
|
||||
.column.push-right {
|
||||
margin-left: auto;
|
||||
}
|
||||
.fade-enter-from .menu,
|
||||
.fade-leave-to .menu {
|
||||
@apply -translate-y-2;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="tag" :size="size">
|
||||
<div class="inline-flex items-center justify-center rounded bg-base-lighter px-2 py-[0.2em] text-sm" :size="size">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</template>
|
||||
@@ -8,12 +8,8 @@
|
||||
const { size = undefined } = defineProps<{ size?: "small" | undefined }>();
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.tag {
|
||||
background-color: var(--scheme-main-ter);
|
||||
border: 1px solid var(--border-color);
|
||||
&[size="small"] {
|
||||
font-size: 0.61rem;
|
||||
}
|
||||
<style scoped lang="postcss">
|
||||
[size="small"] {
|
||||
@apply text-xs;
|
||||
}
|
||||
</style>
|
||||
|
||||
19
assets/components/common/Toggle.vue
Normal file
@@ -0,0 +1,19 @@
|
||||
<template>
|
||||
<label class="label inline-flex cursor-pointer gap-4 font-normal">
|
||||
<input
|
||||
type="checkbox"
|
||||
class="toggle toggle-primary hover:bg-primary-focus"
|
||||
:checked="modelValue"
|
||||
@click="toggle()"
|
||||
/>
|
||||
<slot />
|
||||
</label>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
const { modelValue } = defineModels<{
|
||||
modelValue: boolean;
|
||||
}>();
|
||||
|
||||
const toggle = useToggle(modelValue);
|
||||
</script>
|
||||
@@ -13,11 +13,3 @@ export function persistentVisibleKeys(container: ComputedRef<Container>) {
|
||||
|
||||
const DOZZLE_PINNED_CONTAINERS = "DOZZLE_PINNED_CONTAINERS";
|
||||
export const pinnedContainers = useStorage(DOZZLE_PINNED_CONTAINERS, new Set<string>());
|
||||
|
||||
export function togglePinnedContainer(id: string) {
|
||||
if (pinnedContainers.value.has(id)) {
|
||||
pinnedContainers.value.delete(id);
|
||||
} else {
|
||||
pinnedContainers.value.add(id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<main v-if="!authorizationNeeded">
|
||||
<div v-if="!authorizationNeeded">
|
||||
<mobile-menu v-if="isMobile" @search="showFuzzySearch"></mobile-menu>
|
||||
<splitpanes @resized="onResized($event)">
|
||||
<pane min-size="10" :size="menuWidth" v-if="!isMobile && !collapseNav">
|
||||
@@ -7,7 +7,7 @@
|
||||
</pane>
|
||||
<pane min-size="10">
|
||||
<splitpanes>
|
||||
<pane class="has-min-height router-view">
|
||||
<pane class="router-view min-h-screen">
|
||||
<router-view></router-view>
|
||||
</pane>
|
||||
<template v-if="!isMobile">
|
||||
@@ -26,33 +26,43 @@
|
||||
</splitpanes>
|
||||
<button
|
||||
@click="collapse"
|
||||
class="button is-small is-rounded"
|
||||
:class="{ collapsed: collapseNav }"
|
||||
id="hide-nav"
|
||||
class="btn btn-circle fixed bottom-8 left-4"
|
||||
:class="{ '-left-3': collapseNav }"
|
||||
v-if="!isMobile"
|
||||
>
|
||||
<span class="icon ml-2" v-if="collapseNav">
|
||||
<mdi:light-chevron-right />
|
||||
</span>
|
||||
<span class="icon" v-else>
|
||||
<mdi:light-chevron-left />
|
||||
</span>
|
||||
<mdi:light-chevron-right v-if="collapseNav" />
|
||||
<mdi:light-chevron-left v-else />
|
||||
</button>
|
||||
</main>
|
||||
</div>
|
||||
<dialog ref="modal" class="modal items-start bg-white/20 backdrop:backdrop-blur-sm" @close="open = false">
|
||||
<div class="modal-box max-w-2xl bg-transparent pt-20 shadow-none">
|
||||
<FuzzySearchModal @close="open = false" v-if="open" />
|
||||
</div>
|
||||
<form method="dialog" class="modal-backdrop">
|
||||
<button>close</button>
|
||||
</form>
|
||||
</dialog>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
// @ts-ignore - splitpanes types are not available
|
||||
import { Splitpanes, Pane } from "splitpanes";
|
||||
import { useProgrammatic } from "@oruga-ui/oruga-next";
|
||||
import FuzzySearchModal from "@/components/FuzzySearchModal.vue";
|
||||
|
||||
const { oruga } = useProgrammatic();
|
||||
const { authorizationNeeded } = config;
|
||||
|
||||
const containerStore = useContainerStore();
|
||||
const { activeContainers } = storeToRefs(containerStore);
|
||||
|
||||
const modal = ref<HTMLDialogElement>();
|
||||
const open = ref(false);
|
||||
|
||||
watch(open, () => {
|
||||
if (open.value) {
|
||||
modal.value?.showModal();
|
||||
} else {
|
||||
modal.value?.close();
|
||||
}
|
||||
});
|
||||
|
||||
onKeyStroke("k", (e) => {
|
||||
if ((e.ctrlKey || e.metaKey) && !e.shiftKey) {
|
||||
showFuzzySearch();
|
||||
@@ -61,14 +71,9 @@ onKeyStroke("k", (e) => {
|
||||
});
|
||||
|
||||
function showFuzzySearch() {
|
||||
oruga.modal.open({
|
||||
// parent: this,
|
||||
component: FuzzySearchModal,
|
||||
animation: "false",
|
||||
width: 600,
|
||||
active: true,
|
||||
});
|
||||
open.value = true;
|
||||
}
|
||||
|
||||
function collapse() {
|
||||
collapseNav.value = !collapseNav.value;
|
||||
}
|
||||
@@ -79,14 +84,9 @@ function onResized(e: any) {
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
<style scoped lang="postcss">
|
||||
:deep(.splitpanes--vertical > .splitpanes__splitter) {
|
||||
min-width: 3px;
|
||||
background: var(--border-color);
|
||||
|
||||
&:hover {
|
||||
background: var(--border-hover-color);
|
||||
}
|
||||
@apply min-w-[3px] bg-base-lighter hover:bg-secondary;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 768px) {
|
||||
@@ -94,30 +94,4 @@ function onResized(e: any) {
|
||||
padding-top: 75px;
|
||||
}
|
||||
}
|
||||
|
||||
.button.has-no-border {
|
||||
border-color: transparent !important;
|
||||
}
|
||||
|
||||
.has-min-height {
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
#hide-nav {
|
||||
position: fixed;
|
||||
left: 10px;
|
||||
bottom: 10px;
|
||||
|
||||
&.collapsed {
|
||||
left: -40px;
|
||||
width: 60px;
|
||||
padding-left: 40px;
|
||||
color: var(--text-strong-color);
|
||||
background: var(--scheme-main);
|
||||
|
||||
&:hover {
|
||||
left: -25px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
<template>
|
||||
<main>
|
||||
<router-view></router-view>
|
||||
</main>
|
||||
<div class="hero min-h-screen">
|
||||
<div class="hero-content">
|
||||
<router-view></router-view>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup></script>
|
||||
|
||||
<style scoped lang="scss"></style>
|
||||
|
||||
108
assets/main.css
Normal file
@@ -0,0 +1,108 @@
|
||||
@import "splitpanes/dist/splitpanes.css";
|
||||
|
||||
@define-mixin light {
|
||||
--base-lighter-color: 0 0% 100%;
|
||||
--base-color: 0 0% 97%;
|
||||
--base-darker-color: 0 0% 90%;
|
||||
--base-content-color: 0 0% 21%;
|
||||
--primary-color: 171 100% 41%;
|
||||
--primary-focus-color: 171 100% 31%;
|
||||
--secondary-color: 44 100% 77%;
|
||||
}
|
||||
|
||||
@define-mixin dark {
|
||||
--base-lighter-color: 0 0% 14%;
|
||||
--base-color: 0 0% 7%;
|
||||
--base-darker-color: 0 0% 4%;
|
||||
--base-content-color: 0 0% 86%;
|
||||
--primary-color: 171 100% 41%;
|
||||
--primary-focus-color: 171 100% 31%;
|
||||
--secondary-color: 44 100% 77%;
|
||||
--secondary-focus-color: 44 100% 67%;
|
||||
}
|
||||
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
@layer base {
|
||||
:root {
|
||||
--p: var(--primary-color);
|
||||
--pf: var(--primary-focus-color);
|
||||
--pc: 0 0% 100%;
|
||||
--s: var(--secondary-color);
|
||||
--sf: var(--secondary-focus-color);
|
||||
--sc: 0 0% 4%;
|
||||
--b1: var(--base-lighter-color);
|
||||
--b2: var(--base-color);
|
||||
--b3: var(--base-darker-color);
|
||||
--bc: var(--base-content-color);
|
||||
}
|
||||
html[data-theme="dark"] {
|
||||
@mixin dark;
|
||||
}
|
||||
@media (prefers-color-scheme: dark) {
|
||||
html {
|
||||
@mixin dark;
|
||||
}
|
||||
}
|
||||
html[data-theme="light"] {
|
||||
@mixin light;
|
||||
}
|
||||
@media (prefers-color-scheme: light) {
|
||||
html {
|
||||
@mixin light;
|
||||
}
|
||||
}
|
||||
@media screen and (max-device-width: 480px) {
|
||||
body {
|
||||
-webkit-text-size-adjust: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
h1 {
|
||||
@apply text-3xl;
|
||||
}
|
||||
|
||||
h2 {
|
||||
@apply text-2xl;
|
||||
}
|
||||
|
||||
h3 {
|
||||
@apply text-lg;
|
||||
}
|
||||
|
||||
mark {
|
||||
@apply inline-block rounded-sm bg-secondary;
|
||||
animation: pops 200ms ease-out;
|
||||
}
|
||||
|
||||
@keyframes pops {
|
||||
0% {
|
||||
transform: scale(1.5);
|
||||
}
|
||||
100% {
|
||||
transform: scale(1.05);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@layer components {
|
||||
.input {
|
||||
@apply focus:outline-none;
|
||||
}
|
||||
}
|
||||
|
||||
@layer utilities {
|
||||
@media (max-width: 768px) {
|
||||
.mobile-hidden {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.active-primary {
|
||||
--n: var(--p);
|
||||
--nc: var(--pc);
|
||||
@apply active;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
import "./styles.scss";
|
||||
// import "./styles.scss";
|
||||
import "./main.css";
|
||||
import { createApp, App as VueApp } from "vue";
|
||||
import App from "./App.vue";
|
||||
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
import { type App } from "vue";
|
||||
import { Autocomplete, Button, Dropdown, Switch, Skeleton, Field, Modal, Config } from "@oruga-ui/oruga-next";
|
||||
import { bulmaConfig } from "@oruga-ui/theme-bulma";
|
||||
|
||||
export const install = (app: App) => {
|
||||
app
|
||||
.use(Autocomplete)
|
||||
.use(Button)
|
||||
.use(Dropdown)
|
||||
.use(Switch)
|
||||
.use(Modal)
|
||||
.use(Field)
|
||||
.use(Skeleton)
|
||||
.use(Config, bulmaConfig);
|
||||
};
|
||||
@@ -1,11 +1,8 @@
|
||||
<template>
|
||||
<div class="hero is-halfheight">
|
||||
<div class="hero-body">
|
||||
<div class="container has-text-centered">
|
||||
<h1 class="title">
|
||||
404.
|
||||
<small class="subtitle">{{ $t("error.page-not-found") }}</small>
|
||||
</h1>
|
||||
<div class="hero min-h-screen bg-base-200">
|
||||
<div class="hero-content text-center">
|
||||
<div class="max-w-md">
|
||||
<p class="py-6 text-2xl font-bold">{{ $t("error.page-not-found") }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,10 +1,17 @@
|
||||
<template>
|
||||
<search></search>
|
||||
<log-container :id="id" show-title :scrollable="activeContainers.length > 0" v-if="currentContainer"></log-container>
|
||||
<div v-else-if="ready" class="notification is-warning is-light m-6">
|
||||
<h1 class="title">
|
||||
{{ $t("error.container-not-found") }}
|
||||
</h1>
|
||||
<log-container
|
||||
:id="id"
|
||||
:show-title="true"
|
||||
:scrollable="activeContainers.length > 0"
|
||||
v-if="currentContainer"
|
||||
></log-container>
|
||||
<div v-else-if="ready" class="hero min-h-screen bg-base-200">
|
||||
<div class="hero-content text-center">
|
||||
<div class="max-w-md">
|
||||
<p class="py-6 text-2xl font-bold">{{ $t("error.container-not-found") }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -1,52 +1,31 @@
|
||||
<template>
|
||||
<div class="section tile is-ancestor">
|
||||
<div class="tile is-parent">
|
||||
<div class="tile is-child box">
|
||||
<div class="level-item has-text-centered">
|
||||
<div>
|
||||
<p class="title">{{ runningContainers.length }} / {{ containers.length }}</p>
|
||||
<p class="heading">{{ $t("label.running") }} / {{ $t("label.total-containers") }}</p>
|
||||
</div>
|
||||
<div class="flex flex-col gap-16 px-8 pt-8">
|
||||
<section>
|
||||
<div class="stats grid bg-base-lighter shadow">
|
||||
<div class="stat">
|
||||
<div class="stat-value">{{ runningContainers.length }} / {{ containers.length }}</div>
|
||||
<div class="stat-title">{{ $t("label.running") }} / {{ $t("label.total-containers") }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tile is-parent">
|
||||
<div class="tile is-child box">
|
||||
<div class="level-item has-text-centered">
|
||||
<div>
|
||||
<p class="title">{{ totalCpu }}%</p>
|
||||
<p class="heading">{{ $t("label.total-cpu-usage") }}</p>
|
||||
</div>
|
||||
<div class="stat">
|
||||
<div class="stat-value">{{ totalCpu }}%</div>
|
||||
<div class="stat-title">{{ $t("label.total-cpu-usage") }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tile is-parent">
|
||||
<div class="tile is-child box">
|
||||
<div class="level-item has-text-centered">
|
||||
<div>
|
||||
<p class="title">{{ formatBytes(totalMem) }}</p>
|
||||
<p class="heading">{{ $t("label.total-mem-usage") }}</p>
|
||||
</div>
|
||||
<div class="stat">
|
||||
<div class="stat-value">{{ formatBytes(totalMem) }}</div>
|
||||
<div class="stat-title">{{ $t("label.total-mem-usage") }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tile is-parent">
|
||||
<div class="tile is-child box">
|
||||
<div class="level-item has-text-centered">
|
||||
<div>
|
||||
<p class="title">{{ version }}</p>
|
||||
<p class="heading">{{ $t("label.dozzle-version") }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<section class="section table-container">
|
||||
<div class="box">
|
||||
<div class="stat">
|
||||
<div class="stat-value">{{ version }}</div>
|
||||
<div class="stat-title">{{ $t("label.dozzle-version") }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<container-table :containers="runningContainers"></container-table>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
@@ -87,58 +66,24 @@ watchEffect(() => {
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.panel {
|
||||
border: 1px solid var(--border-color);
|
||||
|
||||
.panel-block,
|
||||
.panel-tabs {
|
||||
border-color: var(--border-color);
|
||||
|
||||
.is-active {
|
||||
border-color: var(--border-hover-color);
|
||||
}
|
||||
|
||||
.name {
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.status {
|
||||
margin-left: auto;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 768px) {
|
||||
.pb-0-is-mobile {
|
||||
padding-bottom: 0 !important;
|
||||
}
|
||||
|
||||
.pt-0-is-mobile {
|
||||
padding-top: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
.icon {
|
||||
padding: 10px 3px;
|
||||
}
|
||||
|
||||
.bar-chart {
|
||||
height: 1.5em;
|
||||
.bar-text {
|
||||
font-size: 0.9em;
|
||||
padding: 0 0.5em;
|
||||
}
|
||||
}
|
||||
|
||||
<style lang="postcss" scoped>
|
||||
:deep(tr td) {
|
||||
padding-top: 1em;
|
||||
padding-bottom: 1em;
|
||||
}
|
||||
|
||||
.stat > div {
|
||||
@apply text-center;
|
||||
}
|
||||
|
||||
.stat-value {
|
||||
@apply font-light;
|
||||
}
|
||||
|
||||
.stat-title {
|
||||
@apply font-light;
|
||||
}
|
||||
|
||||
.section + .section {
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
@@ -1,50 +1,39 @@
|
||||
<template>
|
||||
<div class="hero is-halfheight">
|
||||
<div class="hero-body">
|
||||
<div class="container">
|
||||
<section class="columns is-centered section">
|
||||
<div class="column is-4">
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<form action="" method="post" @submit.prevent="onLogin" ref="form">
|
||||
<div class="field">
|
||||
<label class="label">{{ $t("label.username") }}</label>
|
||||
<div class="control">
|
||||
<input
|
||||
class="input"
|
||||
type="text"
|
||||
name="username"
|
||||
autocomplete="username"
|
||||
v-model="username"
|
||||
autofocus
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<label class="label">{{ $t("label.password") }}</label>
|
||||
<div class="control">
|
||||
<input
|
||||
class="input"
|
||||
type="password"
|
||||
name="password"
|
||||
autocomplete="current-password"
|
||||
v-model="password"
|
||||
/>
|
||||
</div>
|
||||
<p class="help is-danger" v-if="error">{{ $t("error.invalid-auth") }}</p>
|
||||
</div>
|
||||
<div class="field is-grouped is-grouped-centered mt-5">
|
||||
<p class="control">
|
||||
<button class="button is-primary" type="submit">{{ $t("button.login") }}</button>
|
||||
</p>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
<div class="card w-96 flex-shrink-0 bg-base-lighter shadow-2xl">
|
||||
<div class="card-body">
|
||||
<form action="" method="post" @submit.prevent="onLogin" ref="form">
|
||||
<div class="form-control">
|
||||
<label class="label">
|
||||
<span class="label-text"> {{ $t("label.username") }} </span>
|
||||
</label>
|
||||
<input
|
||||
class="input input-bordered"
|
||||
type="text"
|
||||
name="username"
|
||||
autocomplete="username"
|
||||
v-model="username"
|
||||
autofocus
|
||||
/>
|
||||
</div>
|
||||
<div class="form-control">
|
||||
<label class="label">
|
||||
<span class="label-text">Password</span>
|
||||
</label>
|
||||
<input
|
||||
class="input input-bordered"
|
||||
type="password"
|
||||
name="password"
|
||||
autocomplete="current-password"
|
||||
v-model="password"
|
||||
/>
|
||||
</div>
|
||||
<label class="label text-red" v-if="error">
|
||||
{{ $t("error.invalid-auth") }}
|
||||
</label>
|
||||
<div class="form-control mt-6">
|
||||
<button class="btn btn-primary" type="submit">{{ $t("button.login") }}</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<template>
|
||||
<div>
|
||||
<section class="section">
|
||||
<div class="mt-10 flex flex-col gap-8 px-10">
|
||||
<section>
|
||||
<div class="has-underline">
|
||||
<h2 class="title is-4">{{ $t("settings.about") }}</h2>
|
||||
<h2>{{ $t("settings.about") }}</h2>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
@@ -14,120 +14,71 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="section">
|
||||
<section class="flex flex-col gap-4">
|
||||
<div class="has-underline">
|
||||
<h2 class="title is-4">{{ $t("settings.display") }}</h2>
|
||||
<h2>{{ $t("settings.display") }}</h2>
|
||||
</div>
|
||||
|
||||
<div class="item">
|
||||
<o-switch v-model="smallerScrollbars"> {{ $t("settings.small-scrollbars") }} </o-switch>
|
||||
<div>
|
||||
<toggle v-model="smallerScrollbars"> {{ $t("settings.small-scrollbars") }} </toggle>
|
||||
</div>
|
||||
<div class="item">
|
||||
<o-switch v-model="showTimestamp"> {{ $t("settings.show-timesamps") }} </o-switch>
|
||||
<div>
|
||||
<toggle v-model="showTimestamp">{{ $t("settings.show-timesamps") }}</toggle>
|
||||
</div>
|
||||
<div class="item">
|
||||
<o-switch v-model="showStd"> {{ $t("settings.show-std") }} </o-switch>
|
||||
<div>
|
||||
<toggle v-model="showStd">{{ $t("settings.show-std") }}</toggle>
|
||||
</div>
|
||||
|
||||
<div class="item">
|
||||
<o-switch v-model="softWrap"> {{ $t("settings.soft-wrap") }}</o-switch>
|
||||
<div>
|
||||
<toggle v-model="softWrap">{{ $t("settings.soft-wrap") }}</toggle>
|
||||
</div>
|
||||
|
||||
<div class="item">
|
||||
<div class="columns is-vcentered">
|
||||
<div class="column is-narrow">
|
||||
<o-field>
|
||||
<o-dropdown v-model="hourStyle" aria-role="list">
|
||||
<template #trigger>
|
||||
<o-button variant="primary" type="button">
|
||||
<span class="is-capitalized">{{ hourStyle }}</span>
|
||||
<span class="icon">
|
||||
<carbon:caret-down />
|
||||
</span>
|
||||
</o-button>
|
||||
</template>
|
||||
|
||||
<o-dropdown-item :value="value" aria-role="listitem" v-for="value in ['auto', '12', '24']" :key="value">
|
||||
<span class="is-capitalized">{{ value }}</span>
|
||||
</o-dropdown-item>
|
||||
</o-dropdown>
|
||||
</o-field>
|
||||
</div>
|
||||
<div class="column">
|
||||
{{ $t("settings.12-24-format") }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center gap-6">
|
||||
<dropdown
|
||||
v-model="hourStyle"
|
||||
:options="[
|
||||
{ label: 'Auto', value: 'auto' },
|
||||
{ label: '12', value: '12' },
|
||||
{ label: '24', value: '24' },
|
||||
]"
|
||||
/>
|
||||
{{ $t("settings.12-24-format") }}
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="columns is-vcentered">
|
||||
<div class="column is-narrow">
|
||||
<o-field>
|
||||
<o-dropdown v-model="size" aria-role="list">
|
||||
<template #trigger>
|
||||
<o-button variant="primary" type="button">
|
||||
<span class="is-capitalized">{{ size }}</span>
|
||||
<span class="icon">
|
||||
<carbon:caret-down />
|
||||
</span>
|
||||
</o-button>
|
||||
</template>
|
||||
|
||||
<o-dropdown-item
|
||||
:value="value"
|
||||
aria-role="listitem"
|
||||
v-for="value in ['small', 'medium', 'large']"
|
||||
:key="value"
|
||||
>
|
||||
<span class="is-capitalized">{{ value }}</span>
|
||||
</o-dropdown-item>
|
||||
</o-dropdown>
|
||||
</o-field>
|
||||
</div>
|
||||
<div class="column">{{ $t("settings.font-size") }}</div>
|
||||
</div>
|
||||
<div class="flex items-center gap-6">
|
||||
<dropdown
|
||||
v-model="size"
|
||||
:options="[
|
||||
{ label: 'Small', value: 'small' },
|
||||
{ label: 'Medium', value: 'medium' },
|
||||
{ label: 'Large', value: 'large' },
|
||||
]"
|
||||
/>
|
||||
{{ $t("settings.font-size") }}
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="columns is-vcentered">
|
||||
<div class="column is-narrow">
|
||||
<o-field>
|
||||
<o-dropdown v-model="lightTheme" aria-role="list">
|
||||
<template #trigger>
|
||||
<o-button variant="primary" type="button">
|
||||
<span class="is-capitalized">{{ lightTheme }}</span>
|
||||
<span class="icon">
|
||||
<carbon:caret-down />
|
||||
</span>
|
||||
</o-button>
|
||||
</template>
|
||||
|
||||
<o-dropdown-item
|
||||
:value="value"
|
||||
aria-role="listitem"
|
||||
v-for="value in ['auto', 'dark', 'light']"
|
||||
:key="value"
|
||||
>
|
||||
<span class="is-capitalized">{{ value }}</span>
|
||||
</o-dropdown-item>
|
||||
</o-dropdown>
|
||||
</o-field>
|
||||
</div>
|
||||
<div class="column">{{ $t("settings.color-scheme") }}</div>
|
||||
</div>
|
||||
<div class="flex items-center gap-6">
|
||||
<dropdown
|
||||
v-model="lightTheme"
|
||||
:options="[
|
||||
{ label: 'Auto', value: 'auto' },
|
||||
{ label: 'Dark', value: 'dark' },
|
||||
{ label: 'Light', value: 'light' },
|
||||
]"
|
||||
/>
|
||||
{{ $t("settings.color-scheme") }}
|
||||
</div>
|
||||
</section>
|
||||
<section class="section">
|
||||
<section class="flex flex-col gap-2">
|
||||
<div class="has-underline">
|
||||
<h2 class="title is-4">{{ $t("settings.options") }}</h2>
|
||||
<h2>{{ $t("settings.options") }}</h2>
|
||||
</div>
|
||||
<div>
|
||||
<toggle v-model="search">
|
||||
<div>{{ $t("settings.search") }} <key-shortcut char="f" class="align-top"></key-shortcut></div>
|
||||
</toggle>
|
||||
</div>
|
||||
|
||||
<div class="item">
|
||||
<o-switch v-model="search">
|
||||
<span>{{ $t("settings.search") }} <key-shortcut char="f"></key-shortcut></span>
|
||||
</o-switch>
|
||||
</div>
|
||||
|
||||
<div class="item">
|
||||
<o-switch v-model="showAllContainers"> {{ $t("settings.show-stopped-containers") }} </o-switch>
|
||||
<div>
|
||||
<toggle v-model="showAllContainers">{{ $t("settings.show-stopped-containers") }}</toggle>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
@@ -174,35 +125,8 @@ async function fetchNextRelease() {
|
||||
|
||||
fetchNextRelease();
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.title {
|
||||
color: var(--title-color);
|
||||
}
|
||||
|
||||
a.next-release {
|
||||
text-decoration: underline;
|
||||
|
||||
&:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
|
||||
.section {
|
||||
padding: 1rem 1.5rem;
|
||||
}
|
||||
|
||||
<style lang="postcss" scoped>
|
||||
.has-underline {
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
padding: 1em 0px;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.item {
|
||||
padding: 1em 0;
|
||||
}
|
||||
|
||||
code {
|
||||
border-radius: 4px;
|
||||
background-color: #444;
|
||||
@apply mb-4 border-b border-base-content/50 py-4;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -93,8 +93,8 @@ export const useContainerStore = defineStore("container", () => {
|
||||
};
|
||||
|
||||
const currentContainer = (id: Ref<string>) => computed(() => allContainersById.value[id.value]);
|
||||
const appendActiveContainer = ({ id }: Container) => activeContainerIds.value.push(id);
|
||||
const removeActiveContainer = ({ id }: Container) =>
|
||||
const appendActiveContainer = ({ id }: { id: string }) => activeContainerIds.value.push(id);
|
||||
const removeActiveContainer = ({ id }: { id: string }) =>
|
||||
activeContainerIds.value.splice(activeContainerIds.value.indexOf(id), 1);
|
||||
|
||||
return {
|
||||
|
||||
@@ -1,250 +0,0 @@
|
||||
@charset "utf-8";
|
||||
@import "bulma/sass/utilities/initial-variables.sass";
|
||||
|
||||
$body-background-color: var(--body-background-color);
|
||||
|
||||
$scheme-main: var(--scheme-main);
|
||||
$scheme-main-bis: var(--scheme-main-bis);
|
||||
$scheme-main-ter: var(--scheme-main-ter);
|
||||
|
||||
$border: var(--border-color);
|
||||
$border-hover: var(--border-hover-color);
|
||||
|
||||
$menu-item-active-background-color: var(--menu-item-active-background-color);
|
||||
$menu-item-color: var(--menu-item-color);
|
||||
$menu-item-hover-background-color: var(--menu-item-hover-background-color);
|
||||
$menu-item-hover-color: var(--menu-item-hover-color);
|
||||
|
||||
$text-strong: var(--text-strong-color);
|
||||
$text: var(--text-color);
|
||||
$text-light: var(--text-light-color);
|
||||
|
||||
$panel-heading-background-color: var(--panel-heading-background-color);
|
||||
$panel-heading-color: var(--panel-heading-color);
|
||||
|
||||
$link: $turquoise;
|
||||
$link-active: $grey-dark;
|
||||
$link-hover: $yellow;
|
||||
|
||||
$dark-toolbar-color: rgba($black-bis, 0.7);
|
||||
$light-toolbar-color: rgba($grey-darker, 0.7);
|
||||
|
||||
@import "bulma/bulma";
|
||||
@import "@oruga-ui/theme-bulma/dist/scss/components/utils/all.scss";
|
||||
@import "@oruga-ui/theme-bulma/dist/scss/components/autocomplete.scss";
|
||||
@import "@oruga-ui/theme-bulma/dist/scss/components/button.scss";
|
||||
@import "@oruga-ui/theme-bulma/dist/scss/components/modal.scss";
|
||||
@import "@oruga-ui/theme-bulma/dist/scss/components/switch.scss";
|
||||
@import "@oruga-ui/theme-bulma/dist/scss/components/dropdown.scss";
|
||||
@import "@oruga-ui/theme-bulma/dist/scss/components/skeleton.scss";
|
||||
@import "splitpanes/dist/splitpanes.css";
|
||||
|
||||
@mixin dark {
|
||||
--scheme-main: #{$black};
|
||||
--scheme-main-bis: #{$black-bis};
|
||||
--scheme-main-ter: #{$black-ter};
|
||||
|
||||
--border-color: #{$grey-darker};
|
||||
--border-hover-color: var(--secondary-color);
|
||||
--logo-color: var(--secondary-color);
|
||||
|
||||
--primary-color: #{$turquoise};
|
||||
--secondary-color: #{$yellow};
|
||||
|
||||
--body-background-color: #{$black-bis};
|
||||
--action-toolbar-background-color: #{$dark-toolbar-color};
|
||||
--body-color: #{$grey-lighter};
|
||||
|
||||
--menu-item-active-background-color: var(--primary-color);
|
||||
--menu-item-color: hsl(0, 6%, 87%);
|
||||
--menu-item-hover-background-color: #{$white-ter};
|
||||
--menu-item-hover-color: #{$black-ter};
|
||||
|
||||
--panel-heading-background-color: var(--secondary-color);
|
||||
--panel-heading-color: var(--scheme-main-bis);
|
||||
|
||||
--text-strong-color: #{$grey-lightest};
|
||||
--text-color: #{$grey-lighter};
|
||||
--text-light-color: #{$grey};
|
||||
}
|
||||
|
||||
@mixin light {
|
||||
--scheme-main: #{$white};
|
||||
--scheme-main-bis: #{$white-bis};
|
||||
--scheme-main-ter: #{$white-ter};
|
||||
|
||||
--border-color: #{$grey-lighter};
|
||||
--border-hover-color: var(--secondary-color);
|
||||
--logo-color: var(--secondary-color);
|
||||
|
||||
--primary-color: #{$turquoise};
|
||||
--secondary-color: rgb(249 115 22);
|
||||
|
||||
--body-background-color: #{$white-bis};
|
||||
--action-toolbar-background-color: #{$light-toolbar-color};
|
||||
--body-color: #{$grey-darker};
|
||||
|
||||
--menu-item-active-background-color: var(--primary-color);
|
||||
--menu-item-color: #{$grey-dark};
|
||||
--menu-item-hover-background-color: #eee8e7;
|
||||
--menu-item-hover-color: #{$black-ter};
|
||||
|
||||
--panel-heading-background-color: var(--secondary-color);
|
||||
--panel-heading-color: var(--text-strong-color);
|
||||
|
||||
--text-strong-color: #{$grey-dark};
|
||||
--text-color: #{$grey-darker};
|
||||
--text-light-color: #{$grey};
|
||||
}
|
||||
|
||||
[data-theme="dark"] {
|
||||
@include dark;
|
||||
}
|
||||
|
||||
[data-theme="light"] {
|
||||
@include light;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
html {
|
||||
@include dark;
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: light) {
|
||||
html {
|
||||
@include light;
|
||||
}
|
||||
}
|
||||
|
||||
:root {
|
||||
--green-color: #00b5ad;
|
||||
--red-color: #f44336;
|
||||
--purple-color: #9c27b0;
|
||||
--orange-color: #ff9800;
|
||||
--blue-color: #2196f3;
|
||||
}
|
||||
|
||||
.is-red {
|
||||
color: var(--red-color);
|
||||
}
|
||||
|
||||
.is-green {
|
||||
color: var(--green-color);
|
||||
}
|
||||
|
||||
.is-purple {
|
||||
color: var(--purple-color);
|
||||
}
|
||||
|
||||
.is-orange {
|
||||
color: var(--orange-color);
|
||||
}
|
||||
|
||||
.is-blue {
|
||||
color: var(--blue-color);
|
||||
}
|
||||
|
||||
html {
|
||||
overflow-x: unset;
|
||||
overflow-y: unset;
|
||||
scroll-snap-type: y proximity;
|
||||
}
|
||||
|
||||
html.has-custom-scrollbars {
|
||||
::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
display: content;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background-color: rgba(128, 128, 128, 0.33);
|
||||
outline: 1px solid slategrey;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb:active {
|
||||
background-color: #777;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track:hover {
|
||||
background-color: rgba(64, 64, 64, 0.33);
|
||||
}
|
||||
|
||||
section main {
|
||||
scrollbar-color: #353535 transparent;
|
||||
scrollbar-width: thin;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: 770px) {
|
||||
.splitpanes__pane {
|
||||
overflow: unset;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-device-width: 480px) {
|
||||
body {
|
||||
-webkit-text-size-adjust: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.splitpanes__splitter {
|
||||
z-index: 99;
|
||||
}
|
||||
|
||||
.is-ellipsis {
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.modal {
|
||||
z-index: 1000;
|
||||
.modal-background {
|
||||
backdrop-filter: blur(10px);
|
||||
}
|
||||
}
|
||||
|
||||
.button .button-wrapper > span {
|
||||
display: contents;
|
||||
}
|
||||
|
||||
.has-dropshadow {
|
||||
filter: drop-shadow(0 1px 2px rgb(0 0 0 / 0.1)) drop-shadow(0 1px 1px rgb(0 0 0 / 0.06));
|
||||
}
|
||||
|
||||
.has-boxshadow {
|
||||
box-shadow:
|
||||
0 1px 3px 0 rgb(0 0 0 / 0.1),
|
||||
0 1px 2px -1px rgb(0 0 0 / 0.1);
|
||||
}
|
||||
|
||||
mark {
|
||||
border-radius: 2px;
|
||||
background-color: var(--secondary-color);
|
||||
animation: pops 200ms ease-out;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
@keyframes pops {
|
||||
0% {
|
||||
transform: scale(1.5);
|
||||
}
|
||||
100% {
|
||||
transform: scale(1.05);
|
||||
}
|
||||
}
|
||||
|
||||
.button.is-rounded:hover {
|
||||
color: var(--text-strong-color);
|
||||
background: var(--scheme-main-ter);
|
||||
}
|
||||
|
||||
a {
|
||||
transition: color 0.2s ease-in-out;
|
||||
}
|
||||
@@ -3,11 +3,11 @@
|
||||
"type": "module",
|
||||
"devDependencies": {
|
||||
"@netlify/functions": "^2.0.2",
|
||||
"@unocss/preset-typography": "^0.55.7",
|
||||
"@unocss/reset": "^0.55.7",
|
||||
"@unocss/transformer-directives": "^0.55.7",
|
||||
"@unocss/preset-typography": "^0.56.1",
|
||||
"@unocss/reset": "^0.56.1",
|
||||
"@unocss/transformer-directives": "^0.56.1",
|
||||
"dozzle": "workspace:*",
|
||||
"sitemap": "^7.1.1",
|
||||
"unocss": "^0.55.7"
|
||||
"unocss": "^0.56.1"
|
||||
}
|
||||
}
|
||||
|
||||
295
docs/pnpm-lock.yaml
generated
@@ -9,14 +9,14 @@ devDependencies:
|
||||
specifier: ^2.0.2
|
||||
version: 2.0.2
|
||||
'@unocss/preset-typography':
|
||||
specifier: ^0.55.7
|
||||
version: 0.55.7
|
||||
specifier: ^0.56.1
|
||||
version: 0.56.1
|
||||
'@unocss/reset':
|
||||
specifier: ^0.55.7
|
||||
version: 0.55.7
|
||||
specifier: ^0.56.1
|
||||
version: 0.56.1
|
||||
'@unocss/transformer-directives':
|
||||
specifier: ^0.55.7
|
||||
version: 0.55.7
|
||||
specifier: ^0.56.1
|
||||
version: 0.56.1
|
||||
dozzle:
|
||||
specifier: workspace:*
|
||||
version: link:..
|
||||
@@ -24,8 +24,8 @@ devDependencies:
|
||||
specifier: ^7.1.1
|
||||
version: 7.1.1
|
||||
unocss:
|
||||
specifier: ^0.55.7
|
||||
version: 0.55.7(postcss@8.4.28)(vite@4.4.9)
|
||||
specifier: ^0.56.1
|
||||
version: 0.56.1(postcss@8.4.30)(vite@4.4.9)
|
||||
|
||||
packages:
|
||||
|
||||
@@ -44,8 +44,8 @@ packages:
|
||||
find-up: 5.0.0
|
||||
dev: true
|
||||
|
||||
/@antfu/utils@0.7.5:
|
||||
resolution: {integrity: sha512-dlR6LdS+0SzOAPx/TPRhnoi7hE251OVeT2Snw0RguNbBSbjUHdWr0l3vcUUDg26rEysT89kCbtw1lVorBXLLCg==}
|
||||
/@antfu/utils@0.7.6:
|
||||
resolution: {integrity: sha512-pvFiLP2BeOKA/ZOS6jxx4XhKzdVLHDhGlFEaZ2flWWYf2xOqVniqpk38I04DFRyz+L0ASggl7SkItTc+ZLju4w==}
|
||||
dev: true
|
||||
|
||||
/@esbuild/android-arm64@0.18.20:
|
||||
@@ -250,11 +250,11 @@ packages:
|
||||
resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==}
|
||||
dev: true
|
||||
|
||||
/@iconify/utils@2.1.9:
|
||||
resolution: {integrity: sha512-mo+A4n3MwLlWlg1SoSO+Dt6pOPWKElk9sSJ6ZpuzbB9OcjxN8RUWxU3ulPwB1nglErWKRam2x4BAohbYF7FiFA==}
|
||||
/@iconify/utils@2.1.10:
|
||||
resolution: {integrity: sha512-0/+5hxjzCZ9RoYpqxnOzbnpQyMdZRuHcMxPJeuX+x/aZkAAD/N4TajDjAPT7LpX+M0bfLExj/p0bbDkUfp0lrg==}
|
||||
dependencies:
|
||||
'@antfu/install-pkg': 0.1.1
|
||||
'@antfu/utils': 0.7.5
|
||||
'@antfu/utils': 0.7.6
|
||||
'@iconify/types': 2.0.0
|
||||
debug: 4.3.4
|
||||
kolorist: 1.8.0
|
||||
@@ -335,12 +335,12 @@ packages:
|
||||
fastq: 1.15.0
|
||||
dev: true
|
||||
|
||||
/@polka/url@1.0.0-next.21:
|
||||
resolution: {integrity: sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==}
|
||||
/@polka/url@1.0.0-next.23:
|
||||
resolution: {integrity: sha512-C16M+IYz0rgRhWZdCmK+h58JMv8vijAA61gmz2rspCSwKwzBebpdcsiUmwrtJRdphuY30i6BSLEOP8ppbNLyLg==}
|
||||
dev: true
|
||||
|
||||
/@rollup/pluginutils@5.0.3:
|
||||
resolution: {integrity: sha512-hfllNN4a80rwNQ9QCxhxuHCGHMAvabXqxNdaChUSSadMre7t4iEUI6fFAhBOn/eIYTgYVhBv7vCLsAJ4u3lf3g==}
|
||||
/@rollup/pluginutils@5.0.4:
|
||||
resolution: {integrity: sha512-0KJnIoRI8A+a1dqOYLxH8vBf8bphDmty5QvIm2hqm7oFCFYKCAZWWd2hXgMibaPsNDhI0AtpYfQZJG47pt/k4g==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
peerDependencies:
|
||||
rollup: ^1.20.0||^2.0.0||^3.0.0
|
||||
@@ -371,32 +371,32 @@ packages:
|
||||
'@types/node': 18.14.2
|
||||
dev: true
|
||||
|
||||
/@unocss/astro@0.55.7(vite@4.4.9):
|
||||
resolution: {integrity: sha512-mw8r14ArxUQBVCCisAJlF/WsZb650iBsduD/lXMk56N/nQ3MMArCcn62kcAxgZSb5tfIOQGQu/tbR8hEcD8y2g==}
|
||||
/@unocss/astro@0.56.1(vite@4.4.9):
|
||||
resolution: {integrity: sha512-ivWm69J76DRwCiEFM75qR4WPMCC6nyOrUM5iQDTypwKbBX26XlXcYYCN3DLoQTmWdp5f2BubZXAg3KIdgVxrYg==}
|
||||
peerDependencies:
|
||||
vite: ^2.9.0 || ^3.0.0-0 || ^4.0.0
|
||||
peerDependenciesMeta:
|
||||
vite:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@unocss/core': 0.55.7
|
||||
'@unocss/reset': 0.55.7
|
||||
'@unocss/vite': 0.55.7(vite@4.4.9)
|
||||
'@unocss/core': 0.56.1
|
||||
'@unocss/reset': 0.56.1
|
||||
'@unocss/vite': 0.56.1(vite@4.4.9)
|
||||
vite: 4.4.9
|
||||
transitivePeerDependencies:
|
||||
- rollup
|
||||
dev: true
|
||||
|
||||
/@unocss/cli@0.55.7:
|
||||
resolution: {integrity: sha512-ZHX2SR2WQbKfcmgOOHjBLB3V57Ct76Zb76YULzBj2EVX43lX/YDCVG87n6ePDY7rOcjCAthjrFQYCLV5KVLKHg==}
|
||||
/@unocss/cli@0.56.1:
|
||||
resolution: {integrity: sha512-s7lRtPkNw7GXdej3uYKFgfyal3Bq0Ux9oJKQ3rV7ysvY5AMfHs+ayc1EC6vXsAunziJ39dloPrRY5cx1H7abkQ==}
|
||||
engines: {node: '>=14'}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
'@ampproject/remapping': 2.2.1
|
||||
'@rollup/pluginutils': 5.0.3
|
||||
'@unocss/config': 0.55.7
|
||||
'@unocss/core': 0.55.7
|
||||
'@unocss/preset-uno': 0.55.7
|
||||
'@rollup/pluginutils': 5.0.4
|
||||
'@unocss/config': 0.56.1
|
||||
'@unocss/core': 0.56.1
|
||||
'@unocss/preset-uno': 0.56.1
|
||||
cac: 6.7.14
|
||||
chokidar: 3.5.3
|
||||
colorette: 2.0.20
|
||||
@@ -409,154 +409,167 @@ packages:
|
||||
- rollup
|
||||
dev: true
|
||||
|
||||
/@unocss/config@0.55.7:
|
||||
resolution: {integrity: sha512-+X6rPScyFEWbkZyCyM+HfoJhJNN+CEl2n2izWkm0kuDj3w9fY9B3f/0dsk+jmx/gJEI5Y797q9zspNMNDib1AA==}
|
||||
/@unocss/config@0.56.1:
|
||||
resolution: {integrity: sha512-ZwKWtbMfg38laUNwjERkiTo3JKCgpw+hZMBqbbr2N4Rhc1ZaT4EJyQmcc/+P05JoNNr+ueYMoCMOCOtn/wuheQ==}
|
||||
engines: {node: '>=14'}
|
||||
dependencies:
|
||||
'@unocss/core': 0.55.7
|
||||
'@unocss/core': 0.56.1
|
||||
unconfig: 0.3.10
|
||||
dev: true
|
||||
|
||||
/@unocss/core@0.55.7:
|
||||
resolution: {integrity: sha512-c+bWe844Xjlwc1EPwHj0+n3LpntJG7ELPbEOOxNIG+CQdcEX0l1G0rkM8+nKstJ9WJmgpf1HdJQLVMF62HXvhw==}
|
||||
/@unocss/core@0.56.1:
|
||||
resolution: {integrity: sha512-2qmb/+hQ2CXmIgSqaeL6Pw2reO2MxsZlLMFuu71J8T3+UKrkI9NAwkZ4sdb38EoOisVIr2lvE48uc44XBfaOdg==}
|
||||
dev: true
|
||||
|
||||
/@unocss/extractor-arbitrary-variants@0.55.7:
|
||||
resolution: {integrity: sha512-imK2g/frlo5Ag0uVB+C/Psyo5+9AnqhoRAgYa6gyrQ/TJnrnwf+M3jFngU9evIMHw92vig1DGfPa2ZId901DwQ==}
|
||||
/@unocss/extractor-arbitrary-variants@0.56.1:
|
||||
resolution: {integrity: sha512-2vEcVwUTpC0yROjvKGjR3HSE8jaf1cwQqL+Ba5oP+Y4Vrjlf8hqvoSowgVT+wp/ecPH8z82xFNhS+XMOdgXpGA==}
|
||||
dependencies:
|
||||
'@unocss/core': 0.55.7
|
||||
'@unocss/core': 0.56.1
|
||||
dev: true
|
||||
|
||||
/@unocss/inspector@0.55.7:
|
||||
resolution: {integrity: sha512-N0mjZozDDyqx8Mh6C/ZlMTlDzGiq22sXY/hPRX55Cf44WZI4W/ZWajqAAp42B+lw2MN0k1FYEMIAwn9n+xgq/g==}
|
||||
/@unocss/inspector@0.56.1:
|
||||
resolution: {integrity: sha512-PJ3MEwOvUjLaiySPQQKlw0XgwpReNK7c+nDX0D8ZBmUyw3swSn8wSar2cCOLsKLRtKRRp4kz1brM/BaleyYyeg==}
|
||||
dependencies:
|
||||
'@unocss/rule-utils': 0.56.1
|
||||
gzip-size: 6.0.0
|
||||
sirv: 2.0.3
|
||||
dev: true
|
||||
|
||||
/@unocss/postcss@0.55.7(postcss@8.4.28):
|
||||
resolution: {integrity: sha512-53Z/yv/CNdlTqKZQ9gpYRoLZSuzQ28J0SDrGCdzwjLcvHG/FD7/x1S7yxE7cUp/4sjvLL15HSzkWq8vNy6SkwQ==}
|
||||
/@unocss/postcss@0.56.1(postcss@8.4.30):
|
||||
resolution: {integrity: sha512-8jUS5ynopvMbZmdUQhGv+lvKziuAPHHl9LaZzCJ4uHgPOwITNXWTi4dmNbytdYC3iYPQ++8eOph93VPCxdqVsw==}
|
||||
engines: {node: '>=14'}
|
||||
peerDependencies:
|
||||
postcss: ^8.4.21
|
||||
dependencies:
|
||||
'@unocss/config': 0.55.7
|
||||
'@unocss/core': 0.55.7
|
||||
'@unocss/config': 0.56.1
|
||||
'@unocss/core': 0.56.1
|
||||
'@unocss/rule-utils': 0.56.1
|
||||
css-tree: 2.3.1
|
||||
fast-glob: 3.3.1
|
||||
magic-string: 0.30.3
|
||||
postcss: 8.4.28
|
||||
postcss: 8.4.30
|
||||
dev: true
|
||||
|
||||
/@unocss/preset-attributify@0.55.7:
|
||||
resolution: {integrity: sha512-L1sNw3DyM4mymIm4DBTTTOllk8LmhYlWMgDlaAW2MYWygjqDCsp99wRKT2175Ya5xHYBA6XetMoBryZD23qJYQ==}
|
||||
/@unocss/preset-attributify@0.56.1:
|
||||
resolution: {integrity: sha512-z+riyM9Fl+aYReg3cgxDRrI52teOL6ebj1UkMOje5sXuhneEQobUkg3k4Oi9NGTdalO5PU/jwcYCNfVksMPWZg==}
|
||||
dependencies:
|
||||
'@unocss/core': 0.55.7
|
||||
'@unocss/core': 0.56.1
|
||||
dev: true
|
||||
|
||||
/@unocss/preset-icons@0.55.7:
|
||||
resolution: {integrity: sha512-JXLOHkyEKKAjLTqjAxYfhwln05WXilGg3jctkZWKpMNawPaonrGt3kZT12YMuMmOryxk7UcyKB0dtYc+p3QYvw==}
|
||||
/@unocss/preset-icons@0.56.1:
|
||||
resolution: {integrity: sha512-Jwyy7i39Hvt4gf+/vtlIcKucNP2y7IV5nF9KPuDnikho4xS/D24z3lbUclrscbH8XGfRcsUzGHI/y+8gD7zZjQ==}
|
||||
dependencies:
|
||||
'@iconify/utils': 2.1.9
|
||||
'@unocss/core': 0.55.7
|
||||
'@iconify/utils': 2.1.10
|
||||
'@unocss/core': 0.56.1
|
||||
ofetch: 1.3.3
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
/@unocss/preset-mini@0.55.7:
|
||||
resolution: {integrity: sha512-ZCskE2uprjGkpQezEPM6KPMf84rIZEUNc1p2DxWVHaFUPRV24/JSNsO4PsKrQgNIb2dLQxzPNlMzQJI7ssdBXQ==}
|
||||
/@unocss/preset-mini@0.56.1:
|
||||
resolution: {integrity: sha512-hOujmUN5kiA7KCkH1mUFf3cStsa3WZTi3g/I91VQ8EM4S6R7aRvME7LBXlb38z68+pckoDLhOhbN7gSg2iZTjA==}
|
||||
dependencies:
|
||||
'@unocss/core': 0.55.7
|
||||
'@unocss/extractor-arbitrary-variants': 0.55.7
|
||||
'@unocss/core': 0.56.1
|
||||
'@unocss/extractor-arbitrary-variants': 0.56.1
|
||||
'@unocss/rule-utils': 0.56.1
|
||||
dev: true
|
||||
|
||||
/@unocss/preset-tagify@0.55.7:
|
||||
resolution: {integrity: sha512-aDsuN3a/ZirbCDKpFsue9tc8MHs3l0Rl81n2ZOdIrJoZW4YWyydMVl++cz/HERZW81ZySK8EJKwGBaMJMgsnHA==}
|
||||
/@unocss/preset-tagify@0.56.1:
|
||||
resolution: {integrity: sha512-cd1McbaEpoerduOt8dA6MOkVZQIutuF3dHyjrI/pXbDtoyzBWjT9MLEeV77Hlz3S09+9cqGZddBBkqo0WGsM0w==}
|
||||
dependencies:
|
||||
'@unocss/core': 0.55.7
|
||||
'@unocss/core': 0.56.1
|
||||
dev: true
|
||||
|
||||
/@unocss/preset-typography@0.55.7:
|
||||
resolution: {integrity: sha512-hLV4nsgsDIk66pt7Ej4NYUmaGtI2EfGb1h2yl5FmBtdtACrgPq+Skr2Br9Iq+Bj1QFhbsMOWLDdbojFQwBdH6A==}
|
||||
/@unocss/preset-typography@0.56.1:
|
||||
resolution: {integrity: sha512-3p+dWEtMDe8MSPbUZseS94OpdYbv/pMTs2K1NBysE5BjIEVlyxRNWcZ8FC6risAJ1U0Ouctb6BqP6IA8r9BiWQ==}
|
||||
dependencies:
|
||||
'@unocss/core': 0.55.7
|
||||
'@unocss/preset-mini': 0.55.7
|
||||
'@unocss/core': 0.56.1
|
||||
'@unocss/preset-mini': 0.56.1
|
||||
dev: true
|
||||
|
||||
/@unocss/preset-uno@0.55.7:
|
||||
resolution: {integrity: sha512-z4pCxOv/OU1ARo++cvbijWNW2zy/EVTMqJXa+SEep9b99wFXPQE3gaPvLdURp/e5f1PoxVyPZ6JiBknbClSDuA==}
|
||||
/@unocss/preset-uno@0.56.1:
|
||||
resolution: {integrity: sha512-rNnjpmnfrP/1P462dyELBQHe5NDlFSrJevwjCpAOeFXdO0XCCULpHokuaovZYwesNvzzWu+cZequya38n5hkSw==}
|
||||
dependencies:
|
||||
'@unocss/core': 0.55.7
|
||||
'@unocss/preset-mini': 0.55.7
|
||||
'@unocss/preset-wind': 0.55.7
|
||||
'@unocss/core': 0.56.1
|
||||
'@unocss/preset-mini': 0.56.1
|
||||
'@unocss/preset-wind': 0.56.1
|
||||
'@unocss/rule-utils': 0.56.1
|
||||
dev: true
|
||||
|
||||
/@unocss/preset-web-fonts@0.55.7:
|
||||
resolution: {integrity: sha512-ygAz0540kdBapErW2BcObWfQT/6g0SpVUPYg92PPiZD57CZAvuNXiYTfFMRXd88QrBL1zIrZ6NrzY0NZ645H+w==}
|
||||
/@unocss/preset-web-fonts@0.56.1:
|
||||
resolution: {integrity: sha512-SO2ZjrcFSi02QgQT3UVUtIlZE59A92gB1pzmYTMGZhjhmxqq6aghvBKEC00LfnQ200MRtAawgiZ+5Xysi/XsGg==}
|
||||
dependencies:
|
||||
'@unocss/core': 0.55.7
|
||||
'@unocss/core': 0.56.1
|
||||
ofetch: 1.3.3
|
||||
dev: true
|
||||
|
||||
/@unocss/preset-wind@0.55.7:
|
||||
resolution: {integrity: sha512-vLi0mtYDnvx3uYtBR4fSCR52T59drTUp3XVAAqQTbhvRctnSWm65MWE4G+gqdt2qQ9fM4SVCsxLLaXuJkI2eqw==}
|
||||
/@unocss/preset-wind@0.56.1:
|
||||
resolution: {integrity: sha512-/fR0eYlmezu6R3wWvN5zVNAfOE6rcC1CsEZKH0SdwchMvNDjJNd0rmAechI2BnVBaa3++H2Cz+0AfCDEP8tsjg==}
|
||||
dependencies:
|
||||
'@unocss/core': 0.55.7
|
||||
'@unocss/preset-mini': 0.55.7
|
||||
'@unocss/core': 0.56.1
|
||||
'@unocss/preset-mini': 0.56.1
|
||||
'@unocss/rule-utils': 0.56.1
|
||||
dev: true
|
||||
|
||||
/@unocss/reset@0.55.7:
|
||||
resolution: {integrity: sha512-yvmLhxqUNgf6wue7IvhV/FdrQW9H9LF1Bmmhwwaiz2aV0E74aN4pbuYPZwNq3YafsQvNQ0UdtuXjddY4QMRCPw==}
|
||||
/@unocss/reset@0.56.1:
|
||||
resolution: {integrity: sha512-nfzLKv2W9Y3fZLny6lYTroa/YExczGYHsVPCBPGkVt0TrM0yDA+ZKOHbN93b5myY9hzJ3pHTEQmYFsFwzzr6Kg==}
|
||||
dev: true
|
||||
|
||||
/@unocss/scope@0.55.7:
|
||||
resolution: {integrity: sha512-r0CaS1aSpcC37ztqOJ3qaWIzM6zwdlX8r0rib2vTvWTckw1J0ocVhjNkWRBM9kRWte006JhecdiZzXNHA40akg==}
|
||||
dev: true
|
||||
|
||||
/@unocss/transformer-attributify-jsx-babel@0.55.7:
|
||||
resolution: {integrity: sha512-xl5K/Zg7tLyI6Oee+xHgvBm0gSEviYdBDwaGC4O6cP9VXTBm6waz9NUU6CmmVYKh4dSeLQ1PKNboMeg2nFuJMw==}
|
||||
/@unocss/rule-utils@0.56.1:
|
||||
resolution: {integrity: sha512-mmmbx10eELAyhYZqBWlQFPOafnL1hHp2fo18rUbZLedvMJWds3Z23Q/u3VKEpJnCszNkr03BXVwscR5+ZdF4uw==}
|
||||
engines: {node: '>=14'}
|
||||
dependencies:
|
||||
'@unocss/core': 0.55.7
|
||||
'@unocss/core': 0.56.1
|
||||
dev: true
|
||||
|
||||
/@unocss/transformer-attributify-jsx@0.55.7:
|
||||
resolution: {integrity: sha512-ZyUBc0wguBhd+nbIlcrSYpmzKtqBi+8BII8SK4lIB/Ol1wBboByPTjBENsQkxRyffp5K9VTuZZ/LamFgPGOWDg==}
|
||||
dependencies:
|
||||
'@unocss/core': 0.55.7
|
||||
/@unocss/scope@0.56.1:
|
||||
resolution: {integrity: sha512-qIq/JuibrVOAJw/TCUm54XwHRcDImgrb1abZVuaicFh6fjmpdOi/iglYxoFqXS5gusp0m2vNnOLbaBB4LrPf5Q==}
|
||||
dev: true
|
||||
|
||||
/@unocss/transformer-compile-class@0.55.7:
|
||||
resolution: {integrity: sha512-tiYiT9EG4ucSBvMo+9Hv43GY0YvXQjfQCXDhDm3tcJyreMg6BRMO412eir54RBS+JAdNU0DUoITVYu+PkF7hLg==}
|
||||
/@unocss/transformer-attributify-jsx-babel@0.56.1:
|
||||
resolution: {integrity: sha512-8+l4tfifHiSnga3iaxqXfAMgEJG7yLphKPDSm6DHEMUqKeia9rn3V/bABx5KZxpMmnH6FoiYboJL4uf5W58a5Q==}
|
||||
dependencies:
|
||||
'@unocss/core': 0.55.7
|
||||
'@unocss/core': 0.56.1
|
||||
dev: true
|
||||
|
||||
/@unocss/transformer-directives@0.55.7:
|
||||
resolution: {integrity: sha512-xNmR40FssHWYJSmJv/9TQC2IdTyZPV8U3Iv/PIuke1zndMwMciclghEFiw0wSeRmhoRI7iFZck5EI/Bokyo7CQ==}
|
||||
/@unocss/transformer-attributify-jsx@0.56.1:
|
||||
resolution: {integrity: sha512-2dQ7immRBnZJQ9aU+VIiAbcFCycXq8yXG2RPd82Pl0tAV8f5DtLbbuTC5mzo5lGOhuXJ+/u+IpuL9xchjOV7WQ==}
|
||||
dependencies:
|
||||
'@unocss/core': 0.55.7
|
||||
'@unocss/core': 0.56.1
|
||||
dev: true
|
||||
|
||||
/@unocss/transformer-compile-class@0.56.1:
|
||||
resolution: {integrity: sha512-v3ICzTWj3oQ1S6qkGzg/oyzrk05ZgdcvjYFSZlgBIu2iUJldBhO0+7ZMuDpniaT21GjJvukLwiWrOF4mYyJCyg==}
|
||||
dependencies:
|
||||
'@unocss/core': 0.56.1
|
||||
dev: true
|
||||
|
||||
/@unocss/transformer-directives@0.56.1:
|
||||
resolution: {integrity: sha512-Pwh+JUxxn8ECqpEWETeD38OON5Y2oYAOC1CFKAyXoK22J7f51THoS07z2rZpDNdQA2T/szxenNCdRt72/NJ/pg==}
|
||||
dependencies:
|
||||
'@unocss/core': 0.56.1
|
||||
'@unocss/rule-utils': 0.56.1
|
||||
css-tree: 2.3.1
|
||||
dev: true
|
||||
|
||||
/@unocss/transformer-variant-group@0.55.7:
|
||||
resolution: {integrity: sha512-uLyZ08XXVriUDenZCTGA3xGgMD3B9GVr6mSz002pDlLpQDi8FcMQTOGg8X4ViCGzS3l03S/+r+JY7kJTpMFa9w==}
|
||||
/@unocss/transformer-variant-group@0.56.1:
|
||||
resolution: {integrity: sha512-UwXNcW00R6MjHZajy8lmSfwWDwhnvd+rF9eRGfcJTEzWr+LtEmgw8SJBr7STCB4ZwRE37NIp4oLLl1jF8omGNg==}
|
||||
dependencies:
|
||||
'@unocss/core': 0.55.7
|
||||
'@unocss/core': 0.56.1
|
||||
dev: true
|
||||
|
||||
/@unocss/vite@0.55.7(vite@4.4.9):
|
||||
resolution: {integrity: sha512-xmdyDnt9Ag4o7DGl22/P6MaB+HSjWOQw9qYYzIefSv3SVUvn3cEhIX/PCWqFp8Kts2HyvAoJLbZmygSf1XdZNQ==}
|
||||
/@unocss/vite@0.56.1(vite@4.4.9):
|
||||
resolution: {integrity: sha512-IztLc304zP2LYQMsP3yVHmLwXlLUgCY3q6Nkqw6Hpds7l5JXBsE7Q19DtNW+4nDOp9wvWhw7CjQLmoh8d+V0lQ==}
|
||||
peerDependencies:
|
||||
vite: ^2.9.0 || ^3.0.0-0 || ^4.0.0
|
||||
dependencies:
|
||||
'@ampproject/remapping': 2.2.1
|
||||
'@rollup/pluginutils': 5.0.3
|
||||
'@unocss/config': 0.55.7
|
||||
'@unocss/core': 0.55.7
|
||||
'@unocss/inspector': 0.55.7
|
||||
'@unocss/scope': 0.55.7
|
||||
'@unocss/transformer-directives': 0.55.7
|
||||
'@rollup/pluginutils': 5.0.4
|
||||
'@unocss/config': 0.56.1
|
||||
'@unocss/core': 0.56.1
|
||||
'@unocss/inspector': 0.56.1
|
||||
'@unocss/scope': 0.56.1
|
||||
'@unocss/transformer-directives': 0.56.1
|
||||
chokidar: 3.5.3
|
||||
fast-glob: 3.3.1
|
||||
magic-string: 0.30.3
|
||||
@@ -815,8 +828,8 @@ packages:
|
||||
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
|
||||
dev: true
|
||||
|
||||
/jiti@1.19.1:
|
||||
resolution: {integrity: sha512-oVhqoRDaBXf7sjkll95LHVS6Myyyb1zaunVwk4Z0+WPSW4gjS0pl01zYKHScTuyEhQsFxV5L4DR5r+YqSyqyyg==}
|
||||
/jiti@1.20.0:
|
||||
resolution: {integrity: sha512-3TV69ZbrvV6U5DfQimop50jE9Dl6J8O1ja1dvBbMba/sZ3YBEQqJ2VZRoQPVnhlzjNtU1vaXRZVrVjU4qtm8yA==}
|
||||
hasBin: true
|
||||
dev: true
|
||||
|
||||
@@ -873,8 +886,8 @@ packages:
|
||||
engines: {node: '>=6'}
|
||||
dev: true
|
||||
|
||||
/mlly@1.4.0:
|
||||
resolution: {integrity: sha512-ua8PAThnTwpprIaU47EPeZ/bPUVp2QYBbWMphUQpVdBI3Lgqzm5KZQ45Agm3YJedHXaIHl6pBGabaLSUPPSptg==}
|
||||
/mlly@1.4.2:
|
||||
resolution: {integrity: sha512-i/Ykufi2t1EZ6NaPLdfnZk2AX8cs0d+mTzVKuPfqPKPatxLApaBoxJQ9x1/uckXtrS/U5oisPMDkNs0yQTaBRg==}
|
||||
dependencies:
|
||||
acorn: 8.10.0
|
||||
pathe: 1.1.1
|
||||
@@ -973,12 +986,12 @@ packages:
|
||||
resolution: {integrity: sha512-nN7pYi0AQqJnoLPC9eHFQ8AcyaixBUOwvqc5TDnIKCMEE6I0y8P7OKA7fPexsXGCGxQDl/cmrLAp26LhcwxZ4A==}
|
||||
dependencies:
|
||||
jsonc-parser: 3.2.0
|
||||
mlly: 1.4.0
|
||||
mlly: 1.4.2
|
||||
pathe: 1.1.1
|
||||
dev: true
|
||||
|
||||
/postcss@8.4.28:
|
||||
resolution: {integrity: sha512-Z7V5j0cq8oEKyejIKfpD8b4eBy9cwW2JWPk0+fB1HOAMsfHbnAXLLS+PfVWlzMSLQaWttKDt607I0XHmpE67Vw==}
|
||||
/postcss@8.4.30:
|
||||
resolution: {integrity: sha512-7ZEao1g4kd68l97aWG/etQKPKq07us0ieSZ2TnFDk11i0ZfDW2AwKHYU8qv4MZKqN2fdBfg+7q0ES06UA73C1g==}
|
||||
engines: {node: ^10 || ^12 || >=14}
|
||||
dependencies:
|
||||
nanoid: 3.3.6
|
||||
@@ -1002,8 +1015,8 @@ packages:
|
||||
engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
|
||||
dev: true
|
||||
|
||||
/rollup@3.28.1:
|
||||
resolution: {integrity: sha512-R9OMQmIHJm9znrU3m3cpE8uhN0fGdXiawME7aZIpQqvpS/85+Vt1Hq1/yVIcYfOmaQiHjvXkQAoJukvLpau6Yw==}
|
||||
/rollup@3.29.2:
|
||||
resolution: {integrity: sha512-CJouHoZ27v6siztc21eEQGo0kIcE5D1gVPA571ez0mMYb25LGYGKnVNXpEj5MGlepmDWGXNjDB5q7uNiPHC11A==}
|
||||
engines: {node: '>=14.18.0', npm: '>=8.0.0'}
|
||||
hasBin: true
|
||||
optionalDependencies:
|
||||
@@ -1040,7 +1053,7 @@ packages:
|
||||
resolution: {integrity: sha512-O9jm9BsID1P+0HOi81VpXPoDxYP374pkOLzACAoyUQ/3OUVndNpsz6wMnY2z+yOxzbllCKZrM+9QrWsv4THnyA==}
|
||||
engines: {node: '>= 10'}
|
||||
dependencies:
|
||||
'@polka/url': 1.0.0-next.21
|
||||
'@polka/url': 1.0.0-next.23
|
||||
mrmime: 1.0.1
|
||||
totalist: 3.0.1
|
||||
dev: true
|
||||
@@ -1085,17 +1098,17 @@ packages:
|
||||
/unconfig@0.3.10:
|
||||
resolution: {integrity: sha512-tj317lhIq2iZF/NXrJnU1t2UaGUKKz1eL1sK2t63Oq66V9BxqvZV12m55fp/fpQJ+DDmVlLgo7cnLVOZkhlO/A==}
|
||||
dependencies:
|
||||
'@antfu/utils': 0.7.5
|
||||
'@antfu/utils': 0.7.6
|
||||
defu: 6.1.2
|
||||
jiti: 1.19.1
|
||||
mlly: 1.4.0
|
||||
jiti: 1.20.0
|
||||
mlly: 1.4.2
|
||||
dev: true
|
||||
|
||||
/unocss@0.55.7(postcss@8.4.28)(vite@4.4.9):
|
||||
resolution: {integrity: sha512-3W9P7vj2EhSk/4oPCHBS0VgrwSf5zZL6Az1/XARVOpBnRJtCM2szFInYxHkMgt9pkZTsW8SFCuk/g+QIJ6A8tg==}
|
||||
/unocss@0.56.1(postcss@8.4.30)(vite@4.4.9):
|
||||
resolution: {integrity: sha512-jjkcyXfW90CUjN4tBV6SrHX9ifi5GQgcwAQlMRB0copJEW3ejM/nyZnRgNexaV7hi7Ao76XMVqCKbOC5B+IuOA==}
|
||||
engines: {node: '>=14'}
|
||||
peerDependencies:
|
||||
'@unocss/webpack': 0.55.7
|
||||
'@unocss/webpack': 0.56.1
|
||||
vite: ^2.9.0 || ^3.0.0-0 || ^4.0.0
|
||||
peerDependenciesMeta:
|
||||
'@unocss/webpack':
|
||||
@@ -1103,26 +1116,26 @@ packages:
|
||||
vite:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@unocss/astro': 0.55.7(vite@4.4.9)
|
||||
'@unocss/cli': 0.55.7
|
||||
'@unocss/core': 0.55.7
|
||||
'@unocss/extractor-arbitrary-variants': 0.55.7
|
||||
'@unocss/postcss': 0.55.7(postcss@8.4.28)
|
||||
'@unocss/preset-attributify': 0.55.7
|
||||
'@unocss/preset-icons': 0.55.7
|
||||
'@unocss/preset-mini': 0.55.7
|
||||
'@unocss/preset-tagify': 0.55.7
|
||||
'@unocss/preset-typography': 0.55.7
|
||||
'@unocss/preset-uno': 0.55.7
|
||||
'@unocss/preset-web-fonts': 0.55.7
|
||||
'@unocss/preset-wind': 0.55.7
|
||||
'@unocss/reset': 0.55.7
|
||||
'@unocss/transformer-attributify-jsx': 0.55.7
|
||||
'@unocss/transformer-attributify-jsx-babel': 0.55.7
|
||||
'@unocss/transformer-compile-class': 0.55.7
|
||||
'@unocss/transformer-directives': 0.55.7
|
||||
'@unocss/transformer-variant-group': 0.55.7
|
||||
'@unocss/vite': 0.55.7(vite@4.4.9)
|
||||
'@unocss/astro': 0.56.1(vite@4.4.9)
|
||||
'@unocss/cli': 0.56.1
|
||||
'@unocss/core': 0.56.1
|
||||
'@unocss/extractor-arbitrary-variants': 0.56.1
|
||||
'@unocss/postcss': 0.56.1(postcss@8.4.30)
|
||||
'@unocss/preset-attributify': 0.56.1
|
||||
'@unocss/preset-icons': 0.56.1
|
||||
'@unocss/preset-mini': 0.56.1
|
||||
'@unocss/preset-tagify': 0.56.1
|
||||
'@unocss/preset-typography': 0.56.1
|
||||
'@unocss/preset-uno': 0.56.1
|
||||
'@unocss/preset-web-fonts': 0.56.1
|
||||
'@unocss/preset-wind': 0.56.1
|
||||
'@unocss/reset': 0.56.1
|
||||
'@unocss/transformer-attributify-jsx': 0.56.1
|
||||
'@unocss/transformer-attributify-jsx-babel': 0.56.1
|
||||
'@unocss/transformer-compile-class': 0.56.1
|
||||
'@unocss/transformer-directives': 0.56.1
|
||||
'@unocss/transformer-variant-group': 0.56.1
|
||||
'@unocss/vite': 0.56.1(vite@4.4.9)
|
||||
vite: 4.4.9
|
||||
transitivePeerDependencies:
|
||||
- postcss
|
||||
@@ -1163,8 +1176,8 @@ packages:
|
||||
optional: true
|
||||
dependencies:
|
||||
esbuild: 0.18.20
|
||||
postcss: 8.4.28
|
||||
rollup: 3.28.1
|
||||
postcss: 8.4.30
|
||||
rollup: 3.29.2
|
||||
optionalDependencies:
|
||||
fsevents: 2.3.3
|
||||
dev: true
|
||||
|
||||
@@ -4,6 +4,6 @@ test("authentication", async ({ page }) => {
|
||||
await page.goto("http://auth:8080/");
|
||||
await page.locator('input[name="username"]').fill("foo");
|
||||
await page.locator('input[name="password"]').fill("bar");
|
||||
await page.getByRole("button", { name: "Login" }).click();
|
||||
await expect(page.locator("[data-label=all].label")).toHaveText("Containers");
|
||||
await page.locator('button[type="submit"]').click();
|
||||
await expect(page.getByTestId("containers")).toHaveText("Containers");
|
||||
});
|
||||
|
||||
@@ -16,7 +16,7 @@ test("has dashboard text", async ({ page }) => {
|
||||
});
|
||||
|
||||
test("click on settings button", async ({ page }) => {
|
||||
await page.getByRole("link", { name: "Settings" }).click();
|
||||
await page.getByTestId("settings").click();
|
||||
await expect(page.getByRole("heading", { name: "About" })).toBeVisible();
|
||||
});
|
||||
|
||||
@@ -34,6 +34,6 @@ test.describe("es locale", () => {
|
||||
test.use({ locale: "es" });
|
||||
|
||||
test("translated text", async ({ page }) => {
|
||||
await expect(page.locator("[data-label=all].label")).toHaveText("Contenedores");
|
||||
await expect(page.getByTestId("containers")).toHaveText("Contenedores");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -9,7 +9,7 @@ test("has right title", async ({ page }) => {
|
||||
});
|
||||
|
||||
test("select running container", async ({ page }) => {
|
||||
await page.locator("ul.menu-list").getByRole("link", { name: "dozzle" }).click();
|
||||
await page.getByTestId("side-menu").getByRole("link", { name: "dozzle" }).click();
|
||||
await expect(page).toHaveURL(/\/container/);
|
||||
await expect(page.getByText("Accepting connections")).toBeVisible();
|
||||
});
|
||||
|
||||
@@ -5,14 +5,20 @@ test.beforeEach(async ({ page }) => {
|
||||
});
|
||||
|
||||
test.describe("default", () => {
|
||||
test("homepage", async ({ page }) => {
|
||||
await expect(page.locator("aside")).toHaveScreenshot({});
|
||||
test("homepage", async ({ page, isMobile }) => {
|
||||
if (isMobile) {
|
||||
await page.getByTestId("hamburger").click();
|
||||
}
|
||||
await expect(page.getByTestId("navigation")).toHaveScreenshot();
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("dark", () => {
|
||||
test.use({ colorScheme: "dark" });
|
||||
test("homepage", async ({ page }) => {
|
||||
await expect(page.locator("aside")).toHaveScreenshot({});
|
||||
test("homepage", async ({ page, isMobile }) => {
|
||||
if (isMobile) {
|
||||
await page.getByTestId("hamburger").click();
|
||||
}
|
||||
await expect(page.getByTestId("navigation")).toHaveScreenshot();
|
||||
});
|
||||
});
|
||||
|
||||
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 9.2 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 8.6 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
@@ -36,6 +36,7 @@ title:
|
||||
button:
|
||||
logout: Ausloggen
|
||||
login: Anmeldung
|
||||
settings: Einstellungen
|
||||
placeholder:
|
||||
search-containers: Suche Container (⌘ + k, ⌃k)
|
||||
settings:
|
||||
@@ -54,6 +55,5 @@ settings:
|
||||
search: Aktiviere die Suche mit Dozzle mit
|
||||
using-version: Du verwendest Dozzle {version}.
|
||||
update-available: >-
|
||||
Eine neue Version ist verfügbar! Aktualisiere auf <a href="{href}" class="next-release"
|
||||
target="_blank" rel="noreferrer noopener">{nextVersion}</a>.
|
||||
Eine neue Version ist verfügbar! Aktualisiere auf <a href="{href}" target="_blank" rel="noreferrer noopener">{nextVersion}</a>.
|
||||
show-std: Zeige stdout und stderr Labels
|
||||
|
||||
@@ -37,6 +37,7 @@ title:
|
||||
button:
|
||||
logout: Logout
|
||||
login: Login
|
||||
settings: Settings
|
||||
placeholder:
|
||||
search-containers: Search containers (⌘ + k, ⌃k)
|
||||
settings:
|
||||
@@ -55,6 +56,5 @@ settings:
|
||||
search: Enable searching with Dozzle using
|
||||
using-version: You are using Dozzle {version}.
|
||||
update-available: >-
|
||||
New version is available! Update to <a href="{href}" class="next-release"
|
||||
target="_blank" rel="noreferrer noopener">{nextVersion}</a>.
|
||||
New version is available! Update to <a href="{href}" target="_blank" rel="noreferrer noopener">{nextVersion}</a>.
|
||||
show-std: Show stdout and stderr labels
|
||||
|
||||
@@ -36,6 +36,7 @@ title:
|
||||
button:
|
||||
logout: Cerrar la sesión
|
||||
login: Iniciar sesión
|
||||
settings: Configuración
|
||||
placeholder:
|
||||
search-containers: Buscar contenedores (⌘ + K, CTRL + K)
|
||||
settings:
|
||||
@@ -55,5 +56,5 @@ settings:
|
||||
using-version: Estás usando Dozzle {version}.
|
||||
update-available: >-
|
||||
¡La nueva versión está disponible! Actualizar a la
|
||||
<a href="{href}" class="next-release" target="_blank" rel="noreferrer noopener">{nextVersion}</a>.
|
||||
<a href="{href}" target="_blank" rel="noreferrer noopener">{nextVersion}</a>.
|
||||
show-std: Mostrar etiquetas de salida estándar y salida de error estándar
|
||||
|
||||
@@ -36,6 +36,7 @@ title:
|
||||
button:
|
||||
logout: Terminar sessão
|
||||
login: Iniciar sessão
|
||||
settings: Configurações
|
||||
placeholder:
|
||||
search-containers: Pesquisar contentores (⌘ + K, CTRL + K)
|
||||
settings:
|
||||
@@ -55,5 +56,5 @@ settings:
|
||||
using-version: Está a usar o Dozzle {version}.
|
||||
update-available: >-
|
||||
Está disponível uma nova versão! Actualização para
|
||||
<a href="{href}" class="next-release" target="_blank" rel="noreferrer noopener">{nextVersion}</a>.
|
||||
<a href="{href}" target="_blank" rel="noreferrer noopener">{nextVersion}</a>.
|
||||
show-std: Mostrar etiquetas de saída padrão e saída de erro padrão
|
||||
|
||||
@@ -36,6 +36,7 @@ title:
|
||||
button:
|
||||
logout: Выйти
|
||||
login: Войти
|
||||
settings: Настройки
|
||||
placeholder:
|
||||
search-containers: Поиск контейнеров (⌘ + k, ⌃k)
|
||||
settings:
|
||||
@@ -53,6 +54,5 @@ settings:
|
||||
search: Включить поиск с помощью Dozzle, используя
|
||||
using-version: Вы используете версию Dozzle {version}.
|
||||
update-available: >-
|
||||
Доступна новая версия! Обновить до <a href="{href}" class="next-release"
|
||||
target="_blank" rel="noreferrer noopener">{nextVersion}</a>.
|
||||
Доступна новая версия! Обновить до <a href="{href}" target="_blank" rel="noreferrer noopener">{nextVersion}</a>.
|
||||
show-std: Показывать метки stdout и stderr
|
||||
|
||||
@@ -36,6 +36,7 @@ title:
|
||||
button:
|
||||
logout: 退出
|
||||
login: 登录
|
||||
settings: 设置
|
||||
placeholder:
|
||||
search-containers: 搜索容器 (⌘ + k, ⌃k)
|
||||
settings:
|
||||
@@ -53,6 +54,5 @@ settings:
|
||||
search: 使用Dozzle启用搜索
|
||||
using-version: 您正在使用Dozzle {version}。
|
||||
update-available: >-
|
||||
新版本可用!更新到 <a href="{href}" class="next-release"
|
||||
target="_blank" rel="noreferrer noopener">{nextVersion}</a>。
|
||||
新版本可用!更新到 <a href="{href}" rel="noreferrer noopener">{nextVersion}</a>。
|
||||
show-std: 显示stdout和stderr标签
|
||||
|
||||
26
package.json
@@ -34,33 +34,40 @@
|
||||
"@iconify-json/octicon": "^1.1.49",
|
||||
"@iconify-json/ph": "^1.1.6",
|
||||
"@intlify/unplugin-vue-i18n": "^1.2.0",
|
||||
"@oruga-ui/oruga-next": "^0.6.0",
|
||||
"@oruga-ui/theme-bulma": "^0.2.11",
|
||||
"@vueuse/components": "^10.4.1",
|
||||
"@vueuse/core": "^10.4.1",
|
||||
"@vueuse/integrations": "^10.4.1",
|
||||
"@vueuse/math": "^10.4.1",
|
||||
"@vueuse/router": "^10.4.1",
|
||||
"ansi-to-html": "^0.7.2",
|
||||
"bulma": "^0.9.4",
|
||||
"autoprefixer": "^10.4.16",
|
||||
"d3-array": "^3.2.4",
|
||||
"d3-ease": "^3.0.1",
|
||||
"d3-scale": "^4.0.2",
|
||||
"d3-selection": "^3.0.0",
|
||||
"d3-shape": "^3.2.0",
|
||||
"d3-transition": "^3.0.1",
|
||||
"daisyui": "^3.7.7",
|
||||
"date-fns": "^2.30.0",
|
||||
"entities": "^4.5.0",
|
||||
"fuse.js": "^6.6.2",
|
||||
"lodash.debounce": "^4.0.8",
|
||||
"pinia": "^2.1.6",
|
||||
"sass": "^1.67.0",
|
||||
"postcss": "^8.4.30",
|
||||
"postcss-mixins": "^9.0.4",
|
||||
"splitpanes": "^3.1.5",
|
||||
"tailwindcss": "^3.3.3",
|
||||
"vite": "4.4.9",
|
||||
"vite-plugin-pages": "^0.31.0",
|
||||
"vite-plugin-vue-layouts": "^0.8.0",
|
||||
"vue": "^3.3.4",
|
||||
"vue-i18n": "^9.4.1",
|
||||
"vue-router": "^4.2.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@iconify-json/ic": "^1.1.14",
|
||||
"@pinia/testing": "^0.1.3",
|
||||
"@playwright/test": "^1.38.0",
|
||||
"@playwright/test": "^1.38.1",
|
||||
"@types/d3-array": "^3.0.7",
|
||||
"@types/d3-ease": "^3.0.0",
|
||||
"@types/d3-scale": "^4.0.4",
|
||||
@@ -68,7 +75,7 @@
|
||||
"@types/d3-shape": "^3.1.2",
|
||||
"@types/d3-transition": "^3.0.4",
|
||||
"@types/lodash.debounce": "^4.0.7",
|
||||
"@types/node": "^20.6.2",
|
||||
"@types/node": "^20.6.3",
|
||||
"@types/semver": "^7.5.2",
|
||||
"@vitejs/plugin-vue": "4.3.4",
|
||||
"@vue/compiler-sfc": "^3.3.4",
|
||||
@@ -81,6 +88,7 @@
|
||||
"jsdom": "^22.1.0",
|
||||
"lint-staged": "^14.0.1",
|
||||
"prettier": "^3.0.3",
|
||||
"prettier-plugin-tailwindcss": "^0.5.4",
|
||||
"simple-git-hooks": "^2.9.0",
|
||||
"ts-node": "^10.9.1",
|
||||
"typescript": "^5.2.2",
|
||||
@@ -91,9 +99,9 @@
|
||||
"vite": "4.4.9",
|
||||
"vite-plugin-pages": "^0.31.0",
|
||||
"vite-plugin-vue-layouts": "^0.8.0",
|
||||
"vitepress": "1.0.0-rc.14",
|
||||
"vitest": "^0.34.4",
|
||||
"vue-tsc": "^1.8.11"
|
||||
"vitepress": "1.0.0-rc.15",
|
||||
"vitest": "^0.34.5",
|
||||
"vue-tsc": "^1.8.13"
|
||||
},
|
||||
"lint-staged": {
|
||||
"*.{js,vue,css,ts,html,md}": [
|
||||
|
||||
1126
pnpm-lock.yaml
generated
8
postcss.config.js
Normal file
@@ -0,0 +1,8 @@
|
||||
module.exports = {
|
||||
plugins: {
|
||||
"postcss-mixins": {},
|
||||
"tailwindcss/nesting": {},
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
};
|
||||
@@ -1,5 +1,5 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<html class="bg-base text-base-content">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
@@ -26,7 +26,7 @@
|
||||
<body>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="is-hidden"
|
||||
class="hidden"
|
||||
version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
|
||||
34
tailwind.config.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import type { Config } from "tailwindcss";
|
||||
import DaisyUI from "daisyui";
|
||||
|
||||
export default {
|
||||
content: ["./assets/**/*.{vue,js,ts}", "./public/index.html"],
|
||||
theme: {
|
||||
extend: {
|
||||
animation: {
|
||||
"bounce-fast": "bounce 0.5s 2 both",
|
||||
},
|
||||
colors: {
|
||||
green: "hsl(177 100% 35%)",
|
||||
red: "hsl(4 90% 58%)",
|
||||
purple: "hsl(291 64% 42%)",
|
||||
blue: "hsl(207 90% 54%)",
|
||||
orange: "hsl(25 95% 53%)",
|
||||
base: "hsl(var(--base-color) / <alpha-value>)",
|
||||
"base-darker": "hsl(var(--base-darker-color) / <alpha-value>)",
|
||||
"base-lighter": "hsl(var(--base-lighter-color) / <alpha-value>)",
|
||||
"base-content": "hsl(var(--base-content-color) / <alpha-value>)",
|
||||
|
||||
primary: "hsl(var(--primary-color) / <alpha-value>)",
|
||||
"primary-focus": "hsl(var(--primary-focus-color) / <alpha-value>)",
|
||||
secondary: "hsl(var(--secondary-color) / <alpha-value>)",
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [DaisyUI],
|
||||
daisyui: {
|
||||
themes: [],
|
||||
base: false,
|
||||
logs: false,
|
||||
},
|
||||
} satisfies Config;
|
||||
@@ -28,13 +28,7 @@ export default defineConfig(() => ({
|
||||
plugins: [
|
||||
VueMacros({
|
||||
plugins: {
|
||||
vue: Vue({
|
||||
template: {
|
||||
compilerOptions: {
|
||||
whitespace: "preserve",
|
||||
},
|
||||
},
|
||||
}),
|
||||
vue: Vue(),
|
||||
},
|
||||
}),
|
||||
Icons({
|
||||
|
||||