chore: upgrades to tailwind v4 and daisyUI v5 🎨 (#3505)
@@ -18,7 +18,7 @@ watchEffect(() => {
|
|||||||
document.documentElement.setAttribute("data-theme", theme);
|
document.documentElement.setAttribute("data-theme", theme);
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
<style lang="postcss">
|
<style>
|
||||||
html.has-custom-scrollbars {
|
html.has-custom-scrollbars {
|
||||||
::-webkit-scrollbar {
|
::-webkit-scrollbar {
|
||||||
width: 8px;
|
width: 8px;
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
type="radio"
|
type="radio"
|
||||||
name="host"
|
name="host"
|
||||||
role="tab"
|
role="tab"
|
||||||
class="tab !rounded"
|
class="tab rounded-sm!"
|
||||||
aria-label="Show All"
|
aria-label="Show All"
|
||||||
v-model="selectedHost"
|
v-model="selectedHost"
|
||||||
:value="null"
|
:value="null"
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
type="radio"
|
type="radio"
|
||||||
name="host"
|
name="host"
|
||||||
role="tab"
|
role="tab"
|
||||||
class="tab !rounded"
|
class="tab rounded-sm!"
|
||||||
:aria-label="host.name"
|
:aria-label="host.name"
|
||||||
v-for="host in hosts"
|
v-for="host in hosts"
|
||||||
:value="host.id"
|
:value="host.id"
|
||||||
@@ -46,7 +46,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<table class="table table-lg bg-base">
|
<table class="table-lg bg-base-200 table">
|
||||||
<thead>
|
<thead>
|
||||||
<tr :data-direction="direction > 0 ? 'asc' : 'desc'">
|
<tr :data-direction="direction > 0 ? 'asc' : 'desc'">
|
||||||
<th
|
<th
|
||||||
@@ -196,7 +196,9 @@ function isVisible(field: keys) {
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="postcss" scoped>
|
<style scoped>
|
||||||
|
@import "@/main.css" reference;
|
||||||
|
|
||||||
[data-icon] {
|
[data-icon] {
|
||||||
display: none;
|
display: none;
|
||||||
transition: transform 0.2s ease-in-out;
|
transition: transform 0.2s ease-in-out;
|
||||||
@@ -206,7 +208,7 @@ function isVisible(field: keys) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
th {
|
th {
|
||||||
@apply border-b-2 border-base-lighter;
|
@apply border-base-100 border-b-2;
|
||||||
&.selected-sort {
|
&.selected-sort {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
@apply border-primary;
|
@apply border-primary;
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="dropdown dropdown-end dropdown-hover">
|
<div class="dropdown dropdown-end dropdown-hover">
|
||||||
<label tabindex="0" class="btn btn-ghost btn-sm w-10 gap-0.5 px-2">
|
<label tabindex="0" class="btn btn-ghost btn-sm w-10 gap-0.5 px-2">
|
||||||
<carbon:circle-solid class="w-2.5 text-red" v-if="streamConfig.stderr" />
|
<carbon:circle-solid class="text-red w-2.5" v-if="streamConfig.stderr" />
|
||||||
<carbon:circle-solid class="w-2.5 text-blue" v-if="streamConfig.stdout" />
|
<carbon:circle-solid class="text-blue w-2.5" v-if="streamConfig.stdout" />
|
||||||
</label>
|
</label>
|
||||||
<ul tabindex="0" class="menu dropdown-content z-50 w-52 rounded-box bg-base p-1 shadow">
|
<ul tabindex="0" class="menu dropdown-content rounded-box bg-base-200 z-50 w-52 p-1 shadow-sm">
|
||||||
<li>
|
<li>
|
||||||
<a @click.prevent="clear()">
|
<a @click.prevent="clear()">
|
||||||
<octicon:trash-24 /> {{ $t("toolbar.clear") }}
|
<octicon:trash-24 /> {{ $t("toolbar.clear") }}
|
||||||
@@ -31,8 +31,8 @@
|
|||||||
<details>
|
<details>
|
||||||
<summary>
|
<summary>
|
||||||
<div class="flex w-4">
|
<div class="flex w-4">
|
||||||
<carbon:circle-solid class="w-2.5 text-red" v-if="streamConfig.stderr" />
|
<carbon:circle-solid class="text-red w-2.5" v-if="streamConfig.stderr" />
|
||||||
<carbon:circle-solid class="w-2.5 text-blue" v-if="streamConfig.stdout" />
|
<carbon:circle-solid class="text-blue w-2.5" v-if="streamConfig.stdout" />
|
||||||
</div>
|
</div>
|
||||||
Streams
|
Streams
|
||||||
</summary>
|
</summary>
|
||||||
@@ -187,9 +187,11 @@ const toggleAllLevels = computed({
|
|||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="postcss">
|
<style scoped>
|
||||||
|
@import "@/main.css" reference;
|
||||||
|
|
||||||
li.line {
|
li.line {
|
||||||
@apply h-px bg-base-content/20;
|
@apply bg-base-content/20 h-px;
|
||||||
}
|
}
|
||||||
|
|
||||||
a {
|
a {
|
||||||
|
|||||||
@@ -14,7 +14,8 @@ defineProps<{
|
|||||||
}>();
|
}>();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="postcss" scoped>
|
<style scoped>
|
||||||
|
@import "@/main.css" reference;
|
||||||
[health="unhealthy"] {
|
[health="unhealthy"] {
|
||||||
@apply text-red;
|
@apply text-red;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<ScrollableView :scrollable="scrollable" v-if="container">
|
<ScrollableView :scrollable="scrollable" v-if="container">
|
||||||
<template #header v-if="showTitle">
|
<template #header v-if="showTitle">
|
||||||
<div class="mx-2 flex items-center gap-2 @container md:ml-4">
|
<div class="@container mx-2 flex items-center gap-2 md:ml-4">
|
||||||
<ContainerTitle :container="container" />
|
<ContainerTitle :container="container" />
|
||||||
<MultiContainerStat class="ml-auto lg:hidden lg:@3xl:flex" :containers="[container]" />
|
<MultiContainerStat class="ml-auto lg:hidden lg:@3xl:flex" :containers="[container]" />
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="flex flex-1 gap-1.5 truncate @container md:gap-2">
|
<div class="@container flex flex-1 gap-1.5 truncate md:gap-2">
|
||||||
<label class="swap swap-rotate size-4">
|
<label class="swap swap-rotate size-4">
|
||||||
<input type="checkbox" v-model="pinned" />
|
<input type="checkbox" v-model="pinned" />
|
||||||
<carbon:star-filled class="swap-on text-secondary" />
|
<carbon:star-filled class="swap-on text-secondary" />
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="dropdown dropdown-open w-full">
|
<div class="dropdown dropdown-open w-full">
|
||||||
<div class="input input-primary flex h-auto items-center">
|
<div class="input input-xl input-primary flex w-full items-center">
|
||||||
<mdi:magnify class="flex size-8" />
|
<mdi:magnify class="flex size-8" />
|
||||||
<input
|
<input
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
class="input input-lg input-ghost flex-1 px-1"
|
class="input-ghost flex-1 px-1"
|
||||||
ref="input"
|
ref="input"
|
||||||
@keydown.down="selectedIndex = Math.min(selectedIndex + 1, data.length - 1)"
|
@keydown.down="selectedIndex = Math.min(selectedIndex + 1, data.length - 1)"
|
||||||
@keydown.up="selectedIndex = Math.max(selectedIndex - 1, 0)"
|
@keydown.up="selectedIndex = Math.max(selectedIndex - 1, 0)"
|
||||||
@@ -21,15 +21,15 @@
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="dropdown-content !relative mt-2 max-h-[calc(100dvh-20rem)] w-full overflow-y-scroll rounded-md border-y-8 border-transparent bg-base-lighter px-2"
|
class="dropdown-content bg-base-100 relative! mt-2 max-h-[calc(100dvh-20rem)] w-full overflow-y-scroll rounded-md border-y-8 border-transparent px-2"
|
||||||
v-if="results.length"
|
v-if="results.length"
|
||||||
>
|
>
|
||||||
<ul tabindex="0" class="menu">
|
<ul tabindex="0" class="menu w-auto">
|
||||||
<li v-for="(result, index) in data" ref="listItems">
|
<li v-for="(result, index) in data" ref="listItems">
|
||||||
<a
|
<a
|
||||||
class="grid auto-cols-max grid-cols-[min-content,auto] gap-2 py-4"
|
class="grid auto-cols-max grid-cols-[min-content_auto] gap-2 py-4"
|
||||||
@click.prevent="selected(result.item)"
|
@click.prevent="selected(result.item)"
|
||||||
:class="index === selectedIndex ? 'focus' : ''"
|
:class="index === selectedIndex ? 'menu-focus' : ''"
|
||||||
>
|
>
|
||||||
<div :class="{ 'text-primary': result.item.state === 'running' }">
|
<div :class="{ 'text-primary': result.item.state === 'running' }">
|
||||||
<template v-if="result.item.type === 'container'">
|
<template v-if="result.item.type === 'container'">
|
||||||
@@ -85,6 +85,15 @@ const { visibleContainers } = storeToRefs(containerStore);
|
|||||||
const swarmStore = useSwarmStore();
|
const swarmStore = useSwarmStore();
|
||||||
const { stacks, services } = storeToRefs(swarmStore);
|
const { stacks, services } = storeToRefs(swarmStore);
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
const dialog = input.value?.closest("dialog");
|
||||||
|
if (dialog) {
|
||||||
|
const animations = dialog.getAnimations();
|
||||||
|
await Promise.all(animations.map((animation) => animation.finished));
|
||||||
|
input.value?.focus();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
type Item = {
|
type Item = {
|
||||||
id: string;
|
id: string;
|
||||||
created: Date;
|
created: Date;
|
||||||
@@ -167,8 +176,6 @@ watch(selectedIndex, () => {
|
|||||||
listItems.value?.[selectedIndex.value].scrollIntoView({ block: "end" });
|
listItems.value?.[selectedIndex.value].scrollIntoView({ block: "end" });
|
||||||
});
|
});
|
||||||
|
|
||||||
useFocus(input, { initialValue: true });
|
|
||||||
|
|
||||||
function selected(item: Item) {
|
function selected(item: Item) {
|
||||||
if (item.type === "container") {
|
if (item.type === "container") {
|
||||||
router.push({ name: "/container/[id]", params: { id: item.id } });
|
router.push({ name: "/container/[id]", params: { id: item.id } });
|
||||||
@@ -204,7 +211,7 @@ function matchedName({ item, matches = [] }: FuseResult<Item>) {
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="postcss">
|
<style scoped>
|
||||||
:deep(mark) {
|
:deep(mark) {
|
||||||
@apply bg-transparent text-inherit underline underline-offset-2;
|
@apply bg-transparent text-inherit underline underline-offset-2;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<ScrollableView :scrollable="scrollable" v-if="group.containers.length && ready">
|
<ScrollableView :scrollable="scrollable" v-if="group.containers.length && ready">
|
||||||
<template #header>
|
<template #header>
|
||||||
<div class="mx-2 flex items-center gap-2 md:ml-4">
|
<div class="mx-2 flex items-center gap-2 md:ml-4">
|
||||||
<div class="flex flex-1 gap-1.5 truncate @container md:gap-2">
|
<div class="@container flex flex-1 gap-1.5 truncate md:gap-2">
|
||||||
<div class="inline-flex font-mono text-sm">
|
<div class="inline-flex font-mono text-sm">
|
||||||
<div class="font-semibold">{{ $t("label.container", group.containers.length) }}</div>
|
<div class="font-semibold">{{ $t("label.container", group.containers.length) }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<ul class="grid gap-4 md:grid-cols-[repeat(auto-fill,minmax(480px,1fr))]">
|
<ul class="grid gap-4 md:grid-cols-[repeat(auto-fill,minmax(480px,1fr))]">
|
||||||
<li v-for="host in hosts" class="card bg-base-lighter">
|
<li v-for="host in hosts" class="card bg-base-100">
|
||||||
<div class="card-body grid auto-cols-auto grid-flow-col justify-between gap-4">
|
<div class="card-body grid auto-cols-auto grid-flow-col justify-between gap-4">
|
||||||
<div class="flex flex-col gap-2 overflow-hidden">
|
<div class="flex flex-col gap-2 overflow-hidden">
|
||||||
<div class="flex items-center gap-1 truncate text-xl font-semibold">
|
<div class="flex items-center gap-1 truncate text-xl font-semibold">
|
||||||
@@ -39,15 +39,15 @@
|
|||||||
|
|
||||||
<div class="flex flex-row gap-4 md:gap-8" v-if="weightedStats[host.id]">
|
<div class="flex flex-row gap-4 md:gap-8" v-if="weightedStats[host.id]">
|
||||||
<div
|
<div
|
||||||
class="radial-progress text-sm text-primary [--size:4rem] [--thickness:0.25em] md:text-[1rem] md:[--size:5rem]"
|
class="radial-progress text-primary text-sm transition-none [--size:4rem] [--thickness:0.25em] md:text-base md:[--size:5rem]"
|
||||||
:style="`--value: ${Math.floor((weightedStats[host.id].weighted.totalCPU / (host.nCPU * 100)) * 100)}; `"
|
:style="`--value: ${Math.floor((weightedStats[host.id].weighted.totalCPU / (host.nCPU * 100)) * 100)};`"
|
||||||
role="progressbar"
|
role="progressbar"
|
||||||
>
|
>
|
||||||
{{ weightedStats[host.id].weighted.totalCPU.toFixed(0) }}%
|
{{ weightedStats[host.id].weighted.totalCPU.toFixed(0) }}%
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="radial-progress text-sm text-primary [--size:4rem] [--thickness:0.25em] md:text-[1rem] md:[--size:5rem]"
|
class="radial-progress text-primary text-sm transition-none [--size:4rem] [--thickness:0.25em] md:text-base md:[--size:5rem]"
|
||||||
:style="`--value: ${(weightedStats[host.id].weighted.totalMem / host.memTotal) * 100};`"
|
:style="`--value: ${Math.floor((weightedStats[host.id].weighted.totalMem / host.memTotal) * 100)};`"
|
||||||
role="progressbar"
|
role="progressbar"
|
||||||
>
|
>
|
||||||
{{ formatBytes(weightedStats[host.id].weighted.totalMem, 1) }}
|
{{ formatBytes(weightedStats[host.id].weighted.totalMem, 1) }}
|
||||||
@@ -114,5 +114,3 @@ useIntervalFn(
|
|||||||
{ immediate: true },
|
{ immediate: true },
|
||||||
);
|
);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped></style>
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
<label tabindex="0" class="btn btn-square btn-ghost btn-sm">
|
<label tabindex="0" class="btn btn-square btn-ghost btn-sm">
|
||||||
<ph:dots-three-vertical-bold />
|
<ph:dots-three-vertical-bold />
|
||||||
</label>
|
</label>
|
||||||
<ul tabindex="0" class="menu dropdown-content z-50 w-52 rounded-box bg-base p-1 shadow">
|
<ul tabindex="0" class="menu dropdown-content rounded-box bg-base-200 z-50 w-52 p-1 shadow-sm">
|
||||||
<li>
|
<li>
|
||||||
<a class="text-sm capitalize" @click="toggleShowAllContainers()">
|
<a class="text-sm capitalize" @click="toggleShowAllContainers()">
|
||||||
<mdi:check class="w-4" v-if="showAllContainers" />
|
<mdi:check class="w-4" v-if="showAllContainers" />
|
||||||
@@ -44,7 +44,7 @@
|
|||||||
<template #left>
|
<template #left>
|
||||||
<ul class="menu p-0">
|
<ul class="menu p-0">
|
||||||
<li v-for="host in hosts" :key="host.id">
|
<li v-for="host in hosts" :key="host.id">
|
||||||
<a @click.prevent="setHost(host.id)" :class="{ 'pointer-events-none text-base-content/50': !host.available }">
|
<a @click.prevent="setHost(host.id)" :class="{ 'text-base-content/50 pointer-events-none': !host.available }">
|
||||||
<HostIcon :type="host.type" />
|
<HostIcon :type="host.type" />
|
||||||
{{ host.name }}
|
{{ host.name }}
|
||||||
<span class="badge badge-error badge-xs p-1.5" v-if="!host.available">offline</span>
|
<span class="badge badge-error badge-xs p-1.5" v-if="!host.available">offline</span>
|
||||||
@@ -53,10 +53,10 @@
|
|||||||
</ul>
|
</ul>
|
||||||
</template>
|
</template>
|
||||||
<template #right>
|
<template #right>
|
||||||
<ul class="containers menu p-0 [&_li.menu-title]:px-0">
|
<ul class="containers menu w-full p-0 [&_li.menu-title]:px-0">
|
||||||
<li v-for="{ label, containers, icon } in menuItems" :key="label">
|
<li v-for="{ label, containers, icon } in menuItems" :key="label">
|
||||||
<details :open="!collapsedGroups.has(label)" @toggle="updateCollapsedGroups($event, label)">
|
<details :open="!collapsedGroups.has(label)" @toggle="updateCollapsedGroups($event, label)">
|
||||||
<summary class="font-light text-base-content/80">
|
<summary class="text-base-content/80 font-light">
|
||||||
<component :is="icon" />
|
<component :is="icon" />
|
||||||
{{ label.startsWith("label.") ? $t(label) : label }}
|
{{ label.startsWith("label.") ? $t(label) : label }}
|
||||||
|
|
||||||
@@ -77,7 +77,7 @@
|
|||||||
<Popup>
|
<Popup>
|
||||||
<router-link
|
<router-link
|
||||||
:to="{ name: '/container/[id]', params: { id: item.id } }"
|
:to="{ name: '/container/[id]', params: { id: item.id } }"
|
||||||
active-class="active-primary"
|
active-class="menu-active"
|
||||||
@click.alt.stop.prevent="pinnedStore.pinContainer(item)"
|
@click.alt.stop.prevent="pinnedStore.pinContainer(item)"
|
||||||
:title="item.name"
|
:title="item.name"
|
||||||
class="group auto-cols-[auto_max-content_max-content]"
|
class="group auto-cols-[auto_max-content_max-content]"
|
||||||
@@ -87,7 +87,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<ContainerHealth :health="item.health" />
|
<ContainerHealth :health="item.health" />
|
||||||
<span
|
<span
|
||||||
class="hidden hover:text-secondary group-hover:inline-block"
|
class="hover:text-secondary hidden group-hover:inline-block"
|
||||||
@click.stop.prevent="pinnedStore.pinContainer(item)"
|
@click.stop.prevent="pinnedStore.pinContainer(item)"
|
||||||
v-show="!pinnedStore.isPinned(item)"
|
v-show="!pinnedStore.isPinned(item)"
|
||||||
:title="$t('tooltip.pin-column')"
|
:title="$t('tooltip.pin-column')"
|
||||||
@@ -209,7 +209,7 @@ watchEffect(() => {
|
|||||||
|
|
||||||
const toggleShowAllContainers = () => (showAllContainers.value = !showAllContainers.value);
|
const toggleShowAllContainers = () => (showAllContainers.value = !showAllContainers.value);
|
||||||
</script>
|
</script>
|
||||||
<style scoped lang="postcss">
|
<style scoped>
|
||||||
.menu {
|
.menu {
|
||||||
@apply text-[0.95rem];
|
@apply text-[0.95rem];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div ref="root" class="flex min-h-[1px] justify-center">
|
<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>
|
<span class="loading loading-bars loading-md text-primary mt-4" v-show="isLoading"></span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
<template #trigger>
|
<template #trigger>
|
||||||
<mdi:announcement class="size-6 -rotate-12" />
|
<mdi:announcement class="size-6 -rotate-12" />
|
||||||
<span
|
<span
|
||||||
class="absolute right-px top-0 size-2 rounded-full bg-red"
|
class="bg-red absolute top-0 right-px size-2 rounded-full"
|
||||||
v-if="hasUpdate && latestTag != latest?.tag"
|
v-if="hasUpdate && latestTag != latest?.tag"
|
||||||
></span>
|
></span>
|
||||||
</template>
|
</template>
|
||||||
@@ -28,7 +28,7 @@
|
|||||||
<dropdown class="dropdown-end" v-if="config.user">
|
<dropdown class="dropdown-end" v-if="config.user">
|
||||||
<template #trigger>
|
<template #trigger>
|
||||||
<img
|
<img
|
||||||
class="size-6 max-w-none rounded-full p-px ring-1 ring-base-content/60"
|
class="ring-base-content/60 size-6 max-w-none rounded-full p-px ring-1"
|
||||||
:src="withBase('/api/profile/avatar')"
|
:src="withBase('/api/profile/avatar')"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
@@ -43,7 +43,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<ul class="menu mt-4 p-0">
|
<ul class="menu mt-4 p-0">
|
||||||
<li v-if="config.authProvider === 'simple'">
|
<li v-if="config.authProvider === 'simple'">
|
||||||
<button @click.prevent="logout()" class="p-2 text-primary">{{ $t("button.logout") }}</button>
|
<button @click.prevent="logout()" class="text-primary p-2">{{ $t("button.logout") }}</button>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -29,7 +29,8 @@ const validValues = computed(() => {
|
|||||||
const showDrawer = useDrawer();
|
const showDrawer = useDrawer();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="postcss" scoped>
|
<style scoped>
|
||||||
|
@import "@/main.css" reference;
|
||||||
.text-light {
|
.text-light {
|
||||||
@apply text-base-content/70;
|
@apply text-base-content/70;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,7 +71,8 @@ function redirectNow() {
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="postcss" scoped>
|
<style scoped>
|
||||||
|
@import "@/main.css" reference;
|
||||||
[data-event="container-stopped"] {
|
[data-event="container-stopped"] {
|
||||||
@apply text-red;
|
@apply text-red;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
<InfiniteLoader :onLoadMore="fetchMore" :enabled="!loadingMore && messages.length > 10" />
|
<InfiniteLoader :onLoadMore="fetchMore" :enabled="!loadingMore && messages.length > 10" />
|
||||||
<ul class="flex animate-pulse flex-col gap-4 p-4" v-if="loading || (noLogs && waitingForMoreLog)">
|
<ul class="flex animate-pulse flex-col gap-4 p-4" v-if="loading || (noLogs && waitingForMoreLog)">
|
||||||
<div class="flex flex-row gap-2" v-for="size in sizes">
|
<div class="flex flex-row gap-2" v-for="size in sizes">
|
||||||
<div class="h-3 w-40 shrink-0 rounded-full bg-base-content/50 opacity-50"></div>
|
<div class="bg-base-content/50 h-3 w-40 shrink-0 rounded-full opacity-50"></div>
|
||||||
<div class="h-3 rounded-full bg-base-content/50 opacity-50" :class="size"></div>
|
<div class="bg-base-content/50 h-3 rounded-full opacity-50" :class="size"></div>
|
||||||
</div>
|
</div>
|
||||||
<span class="sr-only">Loading...</span>
|
<span class="sr-only">Loading...</span>
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
@@ -94,4 +94,4 @@ const page = computed(() =>
|
|||||||
results.value.numRows > pageLimit ? results.value.slice(0, pageLimit) : results.value,
|
results.value.numRows > pageLimit ? results.value.slice(0, pageLimit) : results.value,
|
||||||
) as unknown as ComputedRef<Table<Record<string, any>>>;
|
) as unknown as ComputedRef<Table<Record<string, any>>>;
|
||||||
</script>
|
</script>
|
||||||
<style lang="postcss" scoped></style>
|
<style scoped></style>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<Tag size="small" class="!items-start">
|
<Tag size="small" class="items-start!">
|
||||||
<DateTime :date="date" class="whitespace-nowrap text-blue" />
|
<DateTime :date="date" class="text-blue whitespace-nowrap" />
|
||||||
</Tag>
|
</Tag>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<header class="flex items-center gap-4">
|
<header class="flex items-center gap-4">
|
||||||
<Tag :data-level="entry.level" class="uppercase text-white" v-if="entry.level">{{ entry.level }}</Tag>
|
<Tag :data-level="entry.level" class="text-white uppercase" v-if="entry.level">{{ entry.level }}</Tag>
|
||||||
<h1 class="mobile-hidden text-lg">
|
<h1 class="mobile-hidden text-lg">
|
||||||
<DateTime :date="entry.date" />
|
<DateTime :date="entry.date" />
|
||||||
</h1>
|
</h1>
|
||||||
@@ -26,21 +26,21 @@
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="flex flex-col gap-2">
|
<section class="flex flex-col gap-2">
|
||||||
<div class="flex gap-2 font-thin">
|
<div class="flex gap-2">
|
||||||
Raw JSON
|
Raw JSON
|
||||||
|
|
||||||
<UseClipboard v-slot="{ copy, copied }" :source="JSON.stringify(entry.unfilteredMessage)">
|
<UseClipboard v-slot="{ copy, copied }" :source="JSON.stringify(entry.unfilteredMessage)">
|
||||||
<button class="swap swap-flip outline-none" @click="copy()" :class="{ 'hover:swap-active': copied }">
|
<button class="swap outline-hidden" @click="copy()" :class="{ 'hover:swap-active': copied }">
|
||||||
<mdi:check class="swap-on" />
|
<mdi:check class="swap-on" />
|
||||||
<mdi:content-copy class="swap-off" />
|
<mdi:content-copy class="swap-off" />
|
||||||
</button>
|
</button>
|
||||||
</UseClipboard>
|
</UseClipboard>
|
||||||
</div>
|
</div>
|
||||||
<div class="max-h-48 overflow-scroll rounded border border-base-lighter bg-base-darker p-2">
|
<div class="bg-base-200 max-h-48 overflow-scroll rounded-sm border border-white/20 p-2">
|
||||||
<pre v-html="syntaxHighlight(entry.unfilteredMessage)"></pre>
|
<pre v-html="syntaxHighlight(entry.unfilteredMessage)"></pre>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<table class="table table-pin-rows table-fixed" v-if="entry instanceof ComplexLogEntry">
|
<table class="table-pin-rows table table-fixed" v-if="entry instanceof ComplexLogEntry">
|
||||||
<caption class="caption-bottom">
|
<caption class="caption-bottom">
|
||||||
Fields are sortable by dragging and dropping.
|
Fields are sortable by dragging and dropping.
|
||||||
</caption>
|
</caption>
|
||||||
@@ -55,7 +55,7 @@
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody ref="list">
|
<tbody ref="list">
|
||||||
<tr v-for="{ key, value, enabled } in fields" :key="key.join('.')" class="hover">
|
<tr v-for="{ key, value, enabled } in fields" :key="key.join('.')" class="hover">
|
||||||
<td class="cursor-move break-all font-mono">
|
<td class="cursor-move font-mono break-all">
|
||||||
{{ key.join(".") }}
|
{{ key.join(".") }}
|
||||||
</td>
|
</td>
|
||||||
<td class="mobile-hidden truncate">
|
<td class="mobile-hidden truncate">
|
||||||
@@ -164,7 +164,8 @@ function syntaxHighlight(json: any) {
|
|||||||
|
|
||||||
useSortable(list, fields);
|
useSortable(list, fields);
|
||||||
</script>
|
</script>
|
||||||
<style lang="postcss" scoped>
|
<style scoped>
|
||||||
|
@import "@/main.css" reference;
|
||||||
.font-mono {
|
.font-mono {
|
||||||
font-family:
|
font-family:
|
||||||
ui-monospace,
|
ui-monospace,
|
||||||
@@ -178,19 +179,19 @@ useSortable(list, fields);
|
|||||||
}
|
}
|
||||||
|
|
||||||
pre {
|
pre {
|
||||||
:deep(.json-key) {
|
& :deep(.json-key) {
|
||||||
@apply text-blue;
|
@apply text-blue;
|
||||||
}
|
}
|
||||||
:deep(.json-string) {
|
& :deep(.json-string) {
|
||||||
@apply text-green;
|
@apply text-green;
|
||||||
}
|
}
|
||||||
:deep(.json-number) {
|
& :deep(.json-number) {
|
||||||
@apply text-orange;
|
@apply text-orange;
|
||||||
}
|
}
|
||||||
:deep(.json-boolean) {
|
& :deep(.json-boolean) {
|
||||||
@apply text-purple;
|
@apply text-purple;
|
||||||
}
|
}
|
||||||
:deep(.json-null) {
|
& :deep(.json-null) {
|
||||||
@apply text-red;
|
@apply text-red;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,8 @@ defineProps<{
|
|||||||
}>();
|
}>();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="postcss" scoped>
|
<style scoped>
|
||||||
|
@import "@/main.css" reference;
|
||||||
[data-position="start"] {
|
[data-position="start"] {
|
||||||
border-radius: 0.5em 0.5em 0 0;
|
border-radius: 0.5em 0.5em 0 0;
|
||||||
height: 70%;
|
height: 70%;
|
||||||
@@ -33,7 +34,8 @@ defineProps<{
|
|||||||
align-self: flex-start;
|
align-self: flex-start;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<style lang="postcss">
|
<style>
|
||||||
|
@import "@/main.css" reference;
|
||||||
[data-level="debug"],
|
[data-level="debug"],
|
||||||
[data-level="trace"] {
|
[data-level="trace"] {
|
||||||
@apply !bg-purple;
|
@apply !bg-purple;
|
||||||
|
|||||||
@@ -53,7 +53,8 @@ useIntersectionObserver(
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
</script>
|
</script>
|
||||||
<style scoped lang="postcss">
|
<style scoped>
|
||||||
|
@import "@/main.css" reference;
|
||||||
.events {
|
.events {
|
||||||
font-family:
|
font-family:
|
||||||
ui-monospace,
|
ui-monospace,
|
||||||
@@ -66,7 +67,7 @@ useIntersectionObserver(
|
|||||||
monospace;
|
monospace;
|
||||||
|
|
||||||
> li {
|
> li {
|
||||||
@apply flex break-words px-2 py-1 last:snap-end odd:bg-gray-400/[0.07] has-[.clickable]:cursor-pointer has-[.clickable]:hover:bg-primary/10 md:px-4;
|
@apply has-[.clickable]:hover:bg-primary/10 flex px-2 py-1 break-words last:snap-end odd:bg-gray-400/[0.07] has-[.clickable]:cursor-pointer md:px-4;
|
||||||
&:last-child {
|
&:last-child {
|
||||||
scroll-margin-block-end: 5rem;
|
scroll-margin-block-end: 5rem;
|
||||||
}
|
}
|
||||||
@@ -93,5 +94,19 @@ useIntersectionObserver(
|
|||||||
@apply rounded-none;
|
@apply rounded-none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
:deep(mark) {
|
||||||
|
@apply bg-secondary inline-block rounded-xs;
|
||||||
|
animation: pops 200ms ease-out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes pops {
|
||||||
|
0% {
|
||||||
|
transform: scale(1.5);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: scale(1.05);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
:title="t('log_actions.copy_log')"
|
:title="t('log_actions.copy_log')"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="rounded bg-slate-800/60 px-1.5 py-1 text-primary hover:bg-slate-700"
|
class="text-primary rounded-sm bg-slate-800/60 px-1.5 py-1 hover:bg-slate-700"
|
||||||
@click.prevent="copyLogMessageToClipBoard()"
|
@click.prevent="copyLogMessageToClipBoard()"
|
||||||
>
|
>
|
||||||
<carbon:copy-file />
|
<carbon:copy-file />
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<Tag size="small" :std="std" class="!items-start">
|
<Tag size="small" :std="std" class="items-start!">
|
||||||
{{ std }}
|
{{ std }}
|
||||||
</Tag>
|
</Tag>
|
||||||
</template>
|
</template>
|
||||||
@@ -12,7 +12,8 @@ defineProps<{
|
|||||||
}>();
|
}>();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="postcss" scoped>
|
<style scoped>
|
||||||
|
@import "@/main.css" reference;
|
||||||
[std="stdout"] {
|
[std="stdout"] {
|
||||||
@apply text-blue;
|
@apply text-blue;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,4 +39,4 @@ watchEffect(() => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
<style scoped lang="postcss"></style>
|
<style scoped></style>
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="dropdown dropdown-end dropdown-hover">
|
<div class="dropdown dropdown-end dropdown-hover">
|
||||||
<label tabindex="0" class="btn btn-ghost btn-sm gap-0.5 px-2">
|
<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="text-red w-2.5" v-if="streamConfig.stderr" />
|
||||||
<carbon:circle-solid class="w-2.5 text-blue" v-if="streamConfig.stdout" />
|
<carbon:circle-solid class="text-blue w-2.5" v-if="streamConfig.stdout" />
|
||||||
</label>
|
</label>
|
||||||
<ul tabindex="0" class="menu dropdown-content z-50 w-52 rounded-box bg-base p-1 shadow">
|
<ul tabindex="0" class="menu dropdown-content rounded-box bg-base-200 z-50 w-52 p-1 shadow-sm">
|
||||||
<li>
|
<li>
|
||||||
<a @click.prevent="clear()">
|
<a @click.prevent="clear()">
|
||||||
<octicon:trash-24 /> {{ $t("toolbar.clear") }}
|
<octicon:trash-24 /> {{ $t("toolbar.clear") }}
|
||||||
@@ -30,8 +30,8 @@
|
|||||||
>
|
>
|
||||||
<div class="flex size-4 gap-0.5">
|
<div class="flex size-4 gap-0.5">
|
||||||
<template v-if="streamConfig.stderr && streamConfig.stdout">
|
<template v-if="streamConfig.stderr && streamConfig.stdout">
|
||||||
<carbon:circle-solid class="w-2 text-red" />
|
<carbon:circle-solid class="text-red w-2" />
|
||||||
<carbon:circle-solid class="w-2 text-blue" />
|
<carbon:circle-solid class="text-blue w-2" />
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
{{ $t("toolbar.show-all") }}
|
{{ $t("toolbar.show-all") }}
|
||||||
@@ -45,7 +45,7 @@
|
|||||||
"
|
"
|
||||||
>
|
>
|
||||||
<div class="flex size-4 flex-col gap-1">
|
<div class="flex size-4 flex-col gap-1">
|
||||||
<carbon:circle-solid class="w-2 text-blue" v-if="!streamConfig.stderr && streamConfig.stdout" />
|
<carbon:circle-solid class="text-blue w-2" v-if="!streamConfig.stderr && streamConfig.stdout" />
|
||||||
</div>
|
</div>
|
||||||
{{ $t("toolbar.show", { std: "STDOUT" }) }}
|
{{ $t("toolbar.show", { std: "STDOUT" }) }}
|
||||||
</a>
|
</a>
|
||||||
@@ -58,7 +58,7 @@
|
|||||||
"
|
"
|
||||||
>
|
>
|
||||||
<div class="flex size-4 flex-col gap-1">
|
<div class="flex size-4 flex-col gap-1">
|
||||||
<carbon:circle-solid class="w-2 text-red" v-if="streamConfig.stderr && !streamConfig.stdout" />
|
<carbon:circle-solid class="text-red w-2" v-if="streamConfig.stderr && !streamConfig.stdout" />
|
||||||
</div>
|
</div>
|
||||||
{{ $t("toolbar.show", { std: "STDERR" }) }}
|
{{ $t("toolbar.show", { std: "STDERR" }) }}
|
||||||
</a>
|
</a>
|
||||||
@@ -102,9 +102,10 @@ const downloadUrl = computed(() =>
|
|||||||
);
|
);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="postcss">
|
<style scoped>
|
||||||
|
@import "@/main.css" reference;
|
||||||
li.line {
|
li.line {
|
||||||
@apply h-px bg-base-content/20;
|
@apply bg-base-content/20 h-px;
|
||||||
}
|
}
|
||||||
|
|
||||||
a {
|
a {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="tag grid w-40 overflow-hidden rounded text-center text-sm text-white">
|
<div class="tag grid w-40 overflow-hidden rounded-sm text-center text-sm text-white">
|
||||||
<div class="random-color col-start-1 row-start-1 brightness-75"></div>
|
<div class="random-color col-start-1 row-start-1 brightness-75"></div>
|
||||||
<div class="col-start-1 row-start-1 truncate px-2 brightness-100 [direction:rtl]">{{ value }}</div>
|
<div class="col-start-1 row-start-1 truncate px-2 brightness-100 [direction:rtl]">{{ value }}</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -36,7 +36,7 @@ const { value } = defineProps<{
|
|||||||
const color = computed(() => colors[Math.abs(hashCode(value)) % colors.length]);
|
const color = computed(() => colors[Math.abs(hashCode(value)) % colors.length]);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="postcss" scoped>
|
<style scoped>
|
||||||
.random-color {
|
.random-color {
|
||||||
background-color: v-bind(color);
|
background-color: v-bind(color);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<table class="table table-zebra table-pin-rows table-md" v-if="!loading">
|
<table class="table-zebra table-pin-rows table-md table" v-if="!loading">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th v-for="column in columns" :key="column">{{ column }}</th>
|
<th v-for="column in columns" :key="column">{{ column }}</th>
|
||||||
@@ -11,18 +11,18 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<table class="table table-md animate-pulse" v-else>
|
<table class="table-md table animate-pulse" v-else>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th v-for="_ in 3">
|
<th v-for="_ in 3">
|
||||||
<div class="h-4 w-20 animate-pulse bg-base-content/50 opacity-50"></div>
|
<div class="bg-base-content/50 h-4 w-20 animate-pulse opacity-50"></div>
|
||||||
</th>
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr v-for="_ in 9">
|
<tr v-for="_ in 9">
|
||||||
<td v-for="_ in 3">
|
<td v-for="_ in 3">
|
||||||
<div class="h-4 w-20 bg-base-content/50 opacity-20"></div>
|
<div class="bg-base-content/50 h-4 w-20 opacity-20"></div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
<template>
|
<template>
|
||||||
<LogItem :logEntry>
|
<LogItem :logEntry>
|
||||||
<div
|
<div
|
||||||
class="log-wrapper whitespace-pre-wrap [word-break:break-word] group-[.disable-wrap]:whitespace-nowrap"
|
class="log-wrapper [word-break:break-word] whitespace-pre-wrap group-[.disable-wrap]:whitespace-nowrap"
|
||||||
v-html="linkify(colorize(logEntry.message))"
|
v-html="linkify(colorize(logEntry.message))"
|
||||||
></div>
|
></div>
|
||||||
<LogMessageActions
|
<LogMessageActions
|
||||||
class="duration-250 absolute -right-1 opacity-0 transition-opacity delay-150 group-hover/entry:opacity-100"
|
class="absolute -right-1 opacity-0 transition-opacity delay-150 duration-250 group-hover/entry:opacity-100"
|
||||||
:message="() => decodeXML(stripAnsi(logEntry.message))"
|
:message="() => decodeXML(stripAnsi(logEntry.message))"
|
||||||
:log-entry="logEntry"
|
:log-entry="logEntry"
|
||||||
/>
|
/>
|
||||||
@@ -34,7 +34,8 @@ const linkify = (text: string) =>
|
|||||||
text.replace(urlPattern, (url) => `<a href="${url}" target="_blank" rel="noopener noreferrer">${url}</a>`);
|
text.replace(urlPattern, (url) => `<a href="${url}" target="_blank" rel="noopener noreferrer">${url}</a>`);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="postcss">
|
<style scoped>
|
||||||
|
@import "@/main.css" reference;
|
||||||
.log-wrapper :deep(a) {
|
.log-wrapper :deep(a) {
|
||||||
@apply text-primary underline-offset-4 hover:underline;
|
@apply text-primary underline-offset-4 hover:underline;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<div class="my-4 flex-1 text-center">
|
<div class="my-4 flex-1 text-center">
|
||||||
<div class="relative">
|
<div class="relative">
|
||||||
<ZigZag class="absolute inset-0 mt-2" />
|
<ZigZag class="absolute inset-0 mt-2" />
|
||||||
<span class="relative whitespace-pre-wrap bg-base px-4 py-2 font-bold">
|
<span class="bg-base-200 relative px-4 py-2 font-bold whitespace-pre-wrap">
|
||||||
{{ $t("error.logs-skipped", { total: logEntry.totalSkipped }) }}
|
{{ $t("error.logs-skipped", { total: logEntry.totalSkipped }) }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="relative hover:text-secondary" @mouseenter="mouseOver = true" @mouseleave="mouseOver = false">
|
<div class="hover:text-secondary relative" @mouseenter="mouseOver = true" @mouseleave="mouseOver = false">
|
||||||
<div class="hidden overflow-hidden rounded-sm border border-primary px-px pb-px pt-1 md:flex">
|
<div class="border-primary hidden overflow-hidden rounded-xs border px-px pt-1 pb-px md:flex">
|
||||||
<StatSparkline :data="data" @selected-point="onSelectedPoint" />
|
<StatSparkline :data="data" @selected-point="onSelectedPoint" />
|
||||||
</div>
|
</div>
|
||||||
<div class="inline-flex gap-1 rounded bg-base p-px text-xs md:absolute md:-left-0.5 md:-top-2">
|
<div class="bg-base-200 inline-flex gap-1 rounded-sm p-px text-xs md:absolute md:-top-2 md:-left-0.5">
|
||||||
<div class="font-light uppercase">{{ label }}</div>
|
<div class="font-light uppercase">{{ label }}</div>
|
||||||
<div class="select-none font-bold">
|
<div class="font-bold select-none">
|
||||||
{{ mouseOver ? selectedPoint?.value ?? selectedPoint?.y ?? statValue : statValue }}
|
{{ mouseOver ? (selectedPoint?.value ?? selectedPoint?.y ?? statValue) : statValue }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<svg :width="width" :height="height" @mousemove="onMove" class="group">
|
<svg :width="width" :height="height" @mousemove="onMove" class="group">
|
||||||
<path :d="path" class="fill-primary" />
|
<path :d="path" class="fill-primary" />
|
||||||
<line :x1="lineX" y1="0" :x2="lineX" :y2="height" class="invisible stroke-secondary stroke-2 group-hover:visible" />
|
<line :x1="lineX" y1="0" :x2="lineX" :y2="height" class="stroke-secondary invisible stroke-2 group-hover:visible" />
|
||||||
</svg>
|
</svg>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@@ -7,12 +7,12 @@ exports[`<ContainerEventSource /> > render html correctly > should render dates
|
|||||||
<!--v-if-->
|
<!--v-if-->
|
||||||
<!--v-if-->
|
<!--v-if-->
|
||||||
<!--v-if-->
|
<!--v-if-->
|
||||||
<div data-v-961504e7="" class="tag inline-flex items-center justify-center rounded bg-base-lighter px-2 py-[0.2em] !items-start shrink-0 select-none" size="small">
|
<div class="tag bg-base-100 inline-flex items-center justify-center rounded-sm px-2 py-[0.2em] [[size='small']]:text-[0.8rem] items-start! shrink-0 select-none" size="small">
|
||||||
<div class="inline-flex gap-2 whitespace-nowrap text-blue"><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 class="inline-flex gap-2 text-blue whitespace-nowrap"><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>
|
||||||
<div data-v-e625cddd="" class="mt-1.5 size-2.5 flex-none rounded-lg flex select-none"></div>
|
<div data-v-e625cddd="" class="mt-1.5 size-2.5 flex-none rounded-lg flex select-none"></div>
|
||||||
<div data-v-a49e52d4="" class="log-wrapper whitespace-pre-wrap [word-break:break-word] group-[.disable-wrap]:whitespace-nowrap">foo bar</div>
|
<div data-v-a49e52d4="" class="log-wrapper [word-break:break-word] whitespace-pre-wrap group-[.disable-wrap]:whitespace-nowrap">foo bar</div>
|
||||||
<div data-v-a49e52d4="" class="flex gap-2 duration-250 absolute -right-1 opacity-0 transition-opacity delay-150 group-hover/entry:opacity-100">
|
<div data-v-a49e52d4="" class="flex gap-2 absolute -right-1 opacity-0 transition-opacity delay-150 duration-250 group-hover/entry:opacity-100">
|
||||||
<!--v-if-->
|
<!--v-if-->
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -27,12 +27,12 @@ exports[`<ContainerEventSource /> > render html correctly > should render dates
|
|||||||
<!--v-if-->
|
<!--v-if-->
|
||||||
<!--v-if-->
|
<!--v-if-->
|
||||||
<!--v-if-->
|
<!--v-if-->
|
||||||
<div data-v-961504e7="" class="tag inline-flex items-center justify-center rounded bg-base-lighter px-2 py-[0.2em] !items-start shrink-0 select-none" size="small">
|
<div class="tag bg-base-100 inline-flex items-center justify-center rounded-sm px-2 py-[0.2em] [[size='small']]:text-[0.8rem] items-start! shrink-0 select-none" size="small">
|
||||||
<div class="inline-flex gap-2 whitespace-nowrap text-blue"><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 class="inline-flex gap-2 text-blue whitespace-nowrap"><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>
|
||||||
<div data-v-e625cddd="" class="mt-1.5 size-2.5 flex-none rounded-lg flex select-none"></div>
|
<div data-v-e625cddd="" class="mt-1.5 size-2.5 flex-none rounded-lg flex select-none"></div>
|
||||||
<div data-v-a49e52d4="" class="log-wrapper whitespace-pre-wrap [word-break:break-word] group-[.disable-wrap]:whitespace-nowrap">foo bar</div>
|
<div data-v-a49e52d4="" class="log-wrapper [word-break:break-word] whitespace-pre-wrap group-[.disable-wrap]:whitespace-nowrap">foo bar</div>
|
||||||
<div data-v-a49e52d4="" class="flex gap-2 duration-250 absolute -right-1 opacity-0 transition-opacity delay-150 group-hover/entry:opacity-100">
|
<div data-v-a49e52d4="" class="flex gap-2 absolute -right-1 opacity-0 transition-opacity delay-150 duration-250 group-hover/entry:opacity-100">
|
||||||
<!--v-if-->
|
<!--v-if-->
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -47,12 +47,12 @@ exports[`<ContainerEventSource /> > render html correctly > should render messag
|
|||||||
<!--v-if-->
|
<!--v-if-->
|
||||||
<!--v-if-->
|
<!--v-if-->
|
||||||
<!--v-if-->
|
<!--v-if-->
|
||||||
<div data-v-961504e7="" class="tag inline-flex items-center justify-center rounded bg-base-lighter px-2 py-[0.2em] !items-start shrink-0 select-none" size="small">
|
<div class="tag bg-base-100 inline-flex items-center justify-center rounded-sm px-2 py-[0.2em] [[size='small']]:text-[0.8rem] items-start! shrink-0 select-none" size="small">
|
||||||
<div class="inline-flex gap-2 whitespace-nowrap text-blue"><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 class="inline-flex gap-2 text-blue whitespace-nowrap"><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>
|
||||||
<div data-v-e625cddd="" class="mt-1.5 size-2.5 flex-none rounded-lg flex select-none"></div>
|
<div data-v-e625cddd="" class="mt-1.5 size-2.5 flex-none rounded-lg flex select-none"></div>
|
||||||
<div data-v-a49e52d4="" class="log-wrapper whitespace-pre-wrap [word-break:break-word] group-[.disable-wrap]:whitespace-nowrap">This is a message.</div>
|
<div data-v-a49e52d4="" class="log-wrapper [word-break:break-word] whitespace-pre-wrap group-[.disable-wrap]:whitespace-nowrap">This is a message.</div>
|
||||||
<div data-v-a49e52d4="" class="flex gap-2 duration-250 absolute -right-1 opacity-0 transition-opacity delay-150 group-hover/entry:opacity-100">
|
<div data-v-a49e52d4="" class="flex gap-2 absolute -right-1 opacity-0 transition-opacity delay-150 duration-250 group-hover/entry:opacity-100">
|
||||||
<!--v-if-->
|
<!--v-if-->
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<ScrollableView :scrollable="scrollable" v-if="containers.length && ready">
|
<ScrollableView :scrollable="scrollable" v-if="containers.length && ready">
|
||||||
<template #header>
|
<template #header>
|
||||||
<div class="mx-2 flex items-center gap-2 md:ml-4">
|
<div class="mx-2 flex items-center gap-2 md:ml-4">
|
||||||
<div class="flex flex-1 gap-1.5 truncate @container md:gap-2">
|
<div class="@container flex flex-1 gap-1.5 truncate md:gap-2">
|
||||||
<octicon:container-24 />
|
<octicon:container-24 />
|
||||||
<div class="inline-flex font-mono text-sm">
|
<div class="inline-flex font-mono text-sm">
|
||||||
<div class="font-semibold">{{ containers.length }} containers</div>
|
<div class="font-semibold">{{ containers.length }} containers</div>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<transition name="fade">
|
<transition name="fade">
|
||||||
<div
|
<div
|
||||||
v-show="show && (delayedShow || glopbalShow)"
|
v-show="show && (delayedShow || glopbalShow)"
|
||||||
class="fixed z-50 rounded border border-base-content/20 bg-base-lighter p-4 shadow"
|
class="border-base-content/20 bg-base-100 fixed z-50 rounded-sm border p-4 shadow-sm"
|
||||||
ref="content"
|
ref="content"
|
||||||
>
|
>
|
||||||
<slot name="content"></slot>
|
<slot name="content"></slot>
|
||||||
@@ -45,7 +45,7 @@ useEventListener(() => el.value?.nextElementSibling, "mouseenter", onMouseEnter)
|
|||||||
useEventListener(() => el.value?.nextElementSibling, "mouseleave", onMouseLeave);
|
useEventListener(() => el.value?.nextElementSibling, "mouseleave", onMouseLeave);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="postcss">
|
<style scoped>
|
||||||
.fade-enter-active,
|
.fade-enter-active,
|
||||||
.fade-leave-active {
|
.fade-leave-active {
|
||||||
@apply transition-opacity;
|
@apply transition-opacity;
|
||||||
|
|||||||
@@ -2,21 +2,21 @@
|
|||||||
<ul class="space-y-4 p-2">
|
<ul class="space-y-4 p-2">
|
||||||
<li v-for="release in releases" v-if="releases?.length">
|
<li v-for="release in releases" v-if="releases?.length">
|
||||||
<div class="flex items-baseline gap-1">
|
<div class="flex items-baseline gap-1">
|
||||||
<carbon:warning class="self-center stroke-orange" v-if="release.breaking > 0" />
|
<carbon:warning class="stroke-orange self-center" v-if="release.breaking > 0" />
|
||||||
<a :href="release.htmlUrl" class="link-primary text-lg font-bold" target="_blank" rel="noreferrer noopener">
|
<a :href="release.htmlUrl" class="link-primary text-lg font-bold" target="_blank" rel="noreferrer noopener">
|
||||||
{{ release.name }}
|
{{ release.name }}
|
||||||
</a>
|
</a>
|
||||||
<span class="ml-1 text-xs"><distance-time :date="new Date(release.createdAt)" /></span>
|
<span class="ml-1 text-xs"><distance-time :date="new Date(release.createdAt)" /></span>
|
||||||
<Tag class="ml-auto bg-red px-1 py-1 text-xs" v-if="release.tag === latest?.tag">
|
<Tag class="bg-red ml-auto px-1 py-1 text-xs" v-if="release.tag === latest?.tag">
|
||||||
{{ $t("releases.latest") }}
|
{{ $t("releases.latest") }}
|
||||||
</Tag>
|
</Tag>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-sm text-base-content/80">
|
<div class="text-base-content/80 text-sm">
|
||||||
{{ summary(release) }}
|
{{ summary(release) }}
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
<li v-else>
|
<li v-else>
|
||||||
<div class="text-sm text-base-content/80">
|
<div class="text-base-content/80 text-sm">
|
||||||
{{ $t("releases.no_releases") }}
|
{{ $t("releases.no_releases") }}
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<div class="inline-flex flex-col items-end gap-2" ref="root" v-show="!autoHide || show">
|
<div class="inline-flex flex-col items-end gap-2" ref="root" v-show="!autoHide || show">
|
||||||
<div class="relative inline-block">
|
<div class="relative inline-block">
|
||||||
<svg width="100" height="100" viewBox="0 0 100 100" :class="{ indeterminate }">
|
<svg width="100" height="100" viewBox="0 0 100 100" :class="{ indeterminate }">
|
||||||
<circle r="44" cx="50" cy="50" class="fill-base-darker stroke-primary" />
|
<circle r="44" cx="50" cy="50" class="fill-base-300 stroke-primary" />
|
||||||
</svg>
|
</svg>
|
||||||
<div class="absolute inset-0 flex items-center justify-center font-light">
|
<div class="absolute inset-0 flex items-center justify-center font-light">
|
||||||
<span class="text-4xl">
|
<span class="text-4xl">
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
<span> % </span>
|
<span> % </span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<DistanceTime :date="date" class="whitespace-nowrap text-sm" />
|
<DistanceTime :date="date" class="text-sm whitespace-nowrap" />
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
</transition>
|
||||||
</template>
|
</template>
|
||||||
@@ -41,7 +41,7 @@ watch(
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
</script>
|
</script>
|
||||||
<style scoped lang="postcss">
|
<style scoped>
|
||||||
svg {
|
svg {
|
||||||
filter: drop-shadow(0px 1px 1px rgba(0, 0, 0, 0.2));
|
filter: drop-shadow(0px 1px 1px rgba(0, 0, 0, 0.2));
|
||||||
margin-top: 5px;
|
margin-top: 5px;
|
||||||
|
|||||||
@@ -2,19 +2,19 @@
|
|||||||
<section :class="{ 'h-screen min-h-0': scrollable }" class="flex flex-col">
|
<section :class="{ 'h-screen min-h-0': scrollable }" class="flex flex-col">
|
||||||
<header
|
<header
|
||||||
v-if="$slots.header"
|
v-if="$slots.header"
|
||||||
class="sticky top-[65px] 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"
|
class="border-base-content/10 bg-base-200 sticky top-[55px] z-2 border-b py-2 shadow-[1px_1px_2px_0_rgb(0,0,0,0.05)] md:top-0"
|
||||||
>
|
>
|
||||||
<slot name="header"></slot>
|
<slot name="header"></slot>
|
||||||
</header>
|
</header>
|
||||||
<main :data-scrolling="scrollable ? true : undefined" class="snap-y overflow-auto">
|
<main :data-scrolling="scrollable ? true : undefined" class="snap-y overflow-auto">
|
||||||
<div class="invisible relative md:visible" v-show="scrollContext.paused">
|
<div class="invisible relative md:visible" v-show="scrollContext.paused">
|
||||||
<div class="absolute right-44 top-4">
|
<div class="absolute top-4 right-44">
|
||||||
<ScrollProgress
|
<ScrollProgress
|
||||||
:indeterminate="loadingMore"
|
:indeterminate="loadingMore"
|
||||||
:auto-hide="!loadingMore"
|
:auto-hide="!loadingMore"
|
||||||
:progress="scrollContext.progress"
|
:progress="scrollContext.progress"
|
||||||
:date="scrollContext.currentDate"
|
:date="scrollContext.currentDate"
|
||||||
class="!fixed z-10 min-w-40"
|
class="fixed! z-10 min-w-40"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -28,7 +28,7 @@
|
|||||||
<div class="mr-16 text-right">
|
<div class="mr-16 text-right">
|
||||||
<transition name="fade">
|
<transition name="fade">
|
||||||
<button
|
<button
|
||||||
class="transition-colorsblur-xs dark btn btn-primary fixed bottom-8 rounded p-3 text-primary-content shadow"
|
class="transition-colorsblur-xs dark btn btn-primary text-primary-content fixed bottom-8 rounded-sm p-3 shadow-sm"
|
||||||
:class="hasMore ? 'btn-secondary animate-bounce-fast text-secondary-content' : ''"
|
:class="hasMore ? 'btn-secondary animate-bounce-fast text-secondary-content' : ''"
|
||||||
@click="scrollToBottom()"
|
@click="scrollToBottom()"
|
||||||
v-show="scrollContext.paused"
|
v-show="scrollContext.paused"
|
||||||
@@ -77,7 +77,7 @@ function scrollToBottom(behavior: "auto" | "smooth" = "auto") {
|
|||||||
hasMore.value = false;
|
hasMore.value = false;
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style scoped lang="postcss">
|
<style scoped>
|
||||||
.fade-enter-active,
|
.fade-enter-active,
|
||||||
.fade-leave-active {
|
.fade-leave-active {
|
||||||
@apply transition-opacity;
|
@apply transition-opacity;
|
||||||
|
|||||||
@@ -7,10 +7,7 @@
|
|||||||
ref="container"
|
ref="container"
|
||||||
:style="style"
|
:style="style"
|
||||||
>
|
>
|
||||||
<div
|
<div class="input input-primary flex items-center shadow-lg" :class="!isValidQuery ? 'input-warning' : ''">
|
||||||
class="input input-primary flex h-auto items-center !shadow-lg"
|
|
||||||
:class="!isValidQuery ? 'input-warning' : ''"
|
|
||||||
>
|
|
||||||
<mdi:magnify />
|
<mdi:magnify />
|
||||||
<input
|
<input
|
||||||
class="input input-ghost w-72 flex-1"
|
class="input input-ghost w-72 flex-1"
|
||||||
@@ -57,7 +54,7 @@ onMounted(() => {
|
|||||||
onUnmounted(() => resetSearch());
|
onUnmounted(() => resetSearch());
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="postcss" scoped>
|
<style scoped>
|
||||||
.slide-enter-active,
|
.slide-enter-active,
|
||||||
.slide-leave-active {
|
.slide-leave-active {
|
||||||
transition: all 200ms cubic-bezier(0.175, 0.885, 0.32, 1.275);
|
transition: all 200ms cubic-bezier(0.175, 0.885, 0.32, 1.275);
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<ScrollableView :scrollable="scrollable" v-if="service.name">
|
<ScrollableView :scrollable="scrollable" v-if="service.name">
|
||||||
<template #header>
|
<template #header>
|
||||||
<div class="mx-2 flex items-center gap-2 md:ml-4">
|
<div class="mx-2 flex items-center gap-2 md:ml-4">
|
||||||
<div class="flex flex-1 gap-1.5 truncate @container md:gap-2">
|
<div class="@container flex flex-1 gap-1.5 truncate md:gap-2">
|
||||||
<ph:stack-simple />
|
<ph:stack-simple />
|
||||||
<div class="inline-flex font-mono text-sm">
|
<div class="inline-flex font-mono text-sm">
|
||||||
<div class="font-semibold">{{ service.name }}</div>
|
<div class="font-semibold">{{ service.name }}</div>
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
</Carousel>
|
</Carousel>
|
||||||
</div>
|
</div>
|
||||||
<div role="status" class="flex animate-pulse flex-col gap-4" v-else>
|
<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>
|
<div class="bg-base-content/50 h-3 w-full rounded-full opacity-50" v-for="_ in 9"></div>
|
||||||
<span class="sr-only">Loading...</span>
|
<span class="sr-only">Loading...</span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -35,4 +35,4 @@ watch(
|
|||||||
{ immediate: true },
|
{ immediate: true },
|
||||||
);
|
);
|
||||||
</script>
|
</script>
|
||||||
<style scoped lang="postcss"></style>
|
<style scoped></style>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<aside class="fixed flex h-screen w-[inherit] flex-col gap-4 p-3" data-testid="navigation">
|
<aside class="fixed flex h-screen w-[inherit] flex-col gap-4 p-3" data-testid="navigation">
|
||||||
<h1>
|
<h1>
|
||||||
<router-link :to="{ name: '/' }">
|
<router-link :to="{ name: '/' }">
|
||||||
<LogoWithText class="logo h-16 w-40" />
|
<LogoWithText class="logo [&_.secondary-fill]:fill-secondary [&_.content-fill]:fill-base-content h-16 w-40" />
|
||||||
</router-link>
|
</router-link>
|
||||||
|
|
||||||
<small class="mb-4 block text-xs font-light" v-if="hostname">
|
<small class="mb-4 block text-xs font-light" v-if="hostname">
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
class="input input-sm inline-flex cursor-pointer items-center gap-2 self-start font-light hover:border-primary"
|
class="input input-sm hover:border-primary inline-flex w-auto cursor-pointer items-center gap-2 self-start font-light"
|
||||||
@click="$emit('search')"
|
@click="$emit('search')"
|
||||||
:title="$t('tooltip.search')"
|
:title="$t('tooltip.search')"
|
||||||
data-testid="search"
|
data-testid="search"
|
||||||
@@ -30,14 +30,4 @@ import LogoWithText from "@/logo-text.svg";
|
|||||||
const { hostname } = config;
|
const { hostname } = config;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="postcss">
|
<style scoped></style>
|
||||||
.logo {
|
|
||||||
:deep(.content-fill) {
|
|
||||||
@apply fill-base-content;
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.secondary-fill) {
|
|
||||||
@apply fill-secondary;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<ScrollableView :scrollable="scrollable" v-if="stack.name">
|
<ScrollableView :scrollable="scrollable" v-if="stack.name">
|
||||||
<template #header>
|
<template #header>
|
||||||
<div class="mx-2 flex items-center gap-2 md:ml-4">
|
<div class="mx-2 flex items-center gap-2 md:ml-4">
|
||||||
<div class="flex flex-1 gap-1.5 truncate @container md:gap-2">
|
<div class="@container flex flex-1 gap-1.5 truncate md:gap-2">
|
||||||
<ph:stack />
|
<ph:stack />
|
||||||
<div class="inline-flex font-mono text-sm">
|
<div class="inline-flex font-mono text-sm">
|
||||||
<div class="font-semibold">{{ stack.name }}</div>
|
<div class="font-semibold">{{ stack.name }}</div>
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<ul class="menu p-0 text-[0.95rem]">
|
<ul class="menu w-full p-0 text-[0.95rem]">
|
||||||
<li v-for="{ name, services } in stacks" :key="name">
|
<li v-for="{ name, services } in stacks" :key="name">
|
||||||
<details open>
|
<details open>
|
||||||
<summary class="font-light text-base-content/80">
|
<summary class="text-base-content/80 font-light">
|
||||||
<ph:stack />
|
<ph:stack />
|
||||||
{{ name }}
|
{{ name }}
|
||||||
|
|
||||||
@@ -17,10 +17,7 @@
|
|||||||
</summary>
|
</summary>
|
||||||
<ul>
|
<ul>
|
||||||
<li v-for="service in services" :key="service.name">
|
<li v-for="service in services" :key="service.name">
|
||||||
<router-link
|
<router-link :to="{ name: '/service/[name]', params: { name: service.name } }" active-class="menu-active">
|
||||||
:to="{ name: '/service/[name]', params: { name: service.name } }"
|
|
||||||
active-class="active-primary"
|
|
||||||
>
|
|
||||||
<ph:stack-simple />
|
<ph:stack-simple />
|
||||||
<div class="truncate">
|
<div class="truncate">
|
||||||
{{ service.name }}
|
{{ service.name }}
|
||||||
@@ -33,16 +30,13 @@
|
|||||||
|
|
||||||
<li v-if="serivcesWithoutStacks.length > 0">
|
<li v-if="serivcesWithoutStacks.length > 0">
|
||||||
<details open>
|
<details open>
|
||||||
<summary class="font-light text-base-content/80">
|
<summary class="text-base-content/80 font-light">
|
||||||
<ph:circles-four />
|
<ph:circles-four />
|
||||||
{{ $t("label.services") }}
|
{{ $t("label.services") }}
|
||||||
</summary>
|
</summary>
|
||||||
<ul>
|
<ul>
|
||||||
<li v-for="service in serivcesWithoutStacks" :key="service.name">
|
<li v-for="service in serivcesWithoutStacks" :key="service.name">
|
||||||
<router-link
|
<router-link :to="{ name: '/service/[name]', params: { name: service.name } }" active-class="menu-active">
|
||||||
:to="{ name: '/service/[name]', params: { name: service.name } }"
|
|
||||||
active-class="active-primary"
|
|
||||||
>
|
|
||||||
<ph:stack-simple />
|
<ph:stack-simple />
|
||||||
<div class="truncate">
|
<div class="truncate">
|
||||||
{{ service.name }}
|
{{ service.name }}
|
||||||
@@ -55,13 +49,13 @@
|
|||||||
|
|
||||||
<li v-if="customGroups.length > 0">
|
<li v-if="customGroups.length > 0">
|
||||||
<details open>
|
<details open>
|
||||||
<summary class="font-light text-base-content/80">
|
<summary class="text-base-content/80 font-light">
|
||||||
<ph:bounding-box-fill />
|
<ph:bounding-box-fill />
|
||||||
{{ $t("label.custom-groups") }}
|
{{ $t("label.custom-groups") }}
|
||||||
</summary>
|
</summary>
|
||||||
<ul>
|
<ul>
|
||||||
<li v-for="group in customGroups" :key="group.name">
|
<li v-for="group in customGroups" :key="group.name">
|
||||||
<router-link :to="{ name: '/group/[name]', params: { name: group.name } }" active-class="active-primary">
|
<router-link :to="{ name: '/group/[name]', params: { name: group.name } }" active-class="menu-active">
|
||||||
<ph:stack-simple />
|
<ph:stack-simple />
|
||||||
<div class="truncate">
|
<div class="truncate">
|
||||||
{{ group.name }}
|
{{ group.name }}
|
||||||
@@ -81,7 +75,7 @@ const { stacks, services, customGroups } = storeToRefs(store);
|
|||||||
|
|
||||||
const serivcesWithoutStacks = computed(() => services.value.filter((service) => !service.stack));
|
const serivcesWithoutStacks = computed(() => services.value.filter((service) => !service.stack));
|
||||||
</script>
|
</script>
|
||||||
<style scoped lang="postcss">
|
<style scoped>
|
||||||
.menu {
|
.menu {
|
||||||
@apply text-[0.95rem];
|
@apply text-[0.95rem];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
@click="scrollToItem(index)"
|
@click="scrollToItem(index)"
|
||||||
:class="[
|
:class="[
|
||||||
'size-2 rounded-full transition-all duration-700',
|
'size-2 rounded-full transition-all duration-700',
|
||||||
activeIndex === index ? 'scale-125 bg-primary' : 'bg-base-content/50 hover:bg-base-content',
|
activeIndex === index ? 'bg-primary scale-125' : 'bg-base-content/50 hover:bg-base-content',
|
||||||
]"
|
]"
|
||||||
:aria-label="c.props?.title"
|
:aria-label="c.props?.title"
|
||||||
:title="c.props?.title"
|
:title="c.props?.title"
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
</label>
|
</label>
|
||||||
<div
|
<div
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
class="dropdown-content z-50 mt-1 min-w-52 rounded-box border border-base-content/20 bg-base p-2 shadow"
|
class="dropdown-content rounded-box border-base-content/20 bg-base-200 z-50 mt-1 min-w-52 border p-2 shadow-sm"
|
||||||
>
|
>
|
||||||
<slot name="content"></slot>
|
<slot name="content"></slot>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -3,7 +3,9 @@
|
|||||||
<summary class="btn btn-primary flex-nowrap" v-bind="$attrs">
|
<summary class="btn btn-primary flex-nowrap" v-bind="$attrs">
|
||||||
<slot name="trigger"> {{ label }} <carbon:caret-down /></slot>
|
<slot name="trigger"> {{ label }} <carbon:caret-down /></slot>
|
||||||
</summary>
|
</summary>
|
||||||
<ul class="menu dropdown-content z-50 mt-1 w-52 rounded-box border border-base-content/20 bg-base p-2 shadow">
|
<ul
|
||||||
|
class="menu dropdown-content rounded-box border-base-content/20 bg-base-200 z-50 mt-1 w-52 border p-2 shadow-sm"
|
||||||
|
>
|
||||||
<slot>
|
<slot>
|
||||||
<li v-for="item in options">
|
<li v-for="item in options">
|
||||||
<a @click="update(item.value as T)">
|
<a @click="update(item.value as T)">
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="animate-background h-1 w-1/2 bg-gradient-radial to-transparent to-75%" :class="colorClass"></div>
|
<div class="animate-background h-1 w-1/2 bg-radial to-transparent to-75%" :class="colorClass"></div>
|
||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
const { color = "primary" } = defineProps<{ color: "primary" | "error" | "secondary" }>();
|
const { color = "primary" } = defineProps<{ color: "primary" | "error" | "secondary" }>();
|
||||||
@@ -16,7 +16,7 @@ const colorClass = computed(() => {
|
|||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="postcss">
|
<style scoped>
|
||||||
.animate-background {
|
.animate-background {
|
||||||
animation: gradient-animation 3s ease-out infinite;
|
animation: gradient-animation 3s ease-out infinite;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<label class="label cursor-pointer gap-4">
|
<label class="label cursor-pointer gap-4">
|
||||||
<div class="label-text"><slot name="label" /></div>
|
<div class="flex-1"><slot name="label" /></div>
|
||||||
<slot name="input" />
|
<slot name="input" />
|
||||||
</label>
|
</label>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<nav class="fixed top-0 z-10 w-full border-b border-base-content/20 bg-base p-2" data-testid="navigation">
|
<nav class="border-base-content/20 bg-base-200 fixed top-0 z-10 w-full border-b p-2" data-testid="navigation">
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<router-link :to="{ name: '/' }">
|
<router-link :to="{ name: '/' }">
|
||||||
<Logo class="logo h-8" />
|
<Logo class="logo [&_.secondary-fill]:fill-secondary h-8" />
|
||||||
</router-link>
|
</router-link>
|
||||||
|
|
||||||
<div class="ml-auto flex items-center gap-2">
|
<div class="ml-auto flex items-center gap-2">
|
||||||
@@ -18,7 +18,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<transition name="fade">
|
<transition name="fade">
|
||||||
<div v-show="show" class="flex h-[calc(100svh-65px)]">
|
<div v-show="show" class="flex h-[calc(100svh-55px)]">
|
||||||
<SideMenu class="flex-1" />
|
<SideMenu class="flex-1" />
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
</transition>
|
||||||
@@ -34,7 +34,8 @@ watch(route, () => {
|
|||||||
show.value = false;
|
show.value = false;
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
<style scoped lang="postcss">
|
<style scoped>
|
||||||
|
@import "@/main.css" reference;
|
||||||
.fade-enter-active,
|
.fade-enter-active,
|
||||||
.fade-leave-active {
|
.fade-leave-active {
|
||||||
@apply transition-opacity;
|
@apply transition-opacity;
|
||||||
@@ -54,10 +55,4 @@ watch(route, () => {
|
|||||||
.fade-leave-to > div {
|
.fade-leave-to > div {
|
||||||
@apply -translate-y-10;
|
@apply -translate-y-10;
|
||||||
}
|
}
|
||||||
|
|
||||||
.logo {
|
|
||||||
:deep(.secondary-fill) {
|
|
||||||
@apply fill-secondary;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<dialog ref="panel" class="modal-right modal items-start outline-none backdrop:bg-none">
|
<dialog ref="panel" class="modal-right modal items-start outline-hidden backdrop:bg-none">
|
||||||
<div class="modal-box" :width="width">
|
<div class="modal-box" :width="width">
|
||||||
<form method="dialog">
|
<form method="dialog">
|
||||||
<button class="swap swap-rotate absolute right-4 top-4 outline-none hover:swap-active">
|
<button class="swap swap-rotate hover:swap-active absolute top-4 right-4 outline-hidden">
|
||||||
<mdi:keyboard-esc class="swap-off" />
|
<mdi:keyboard-esc class="swap-off" />
|
||||||
<mdi:close class="swap-on" />
|
<mdi:close class="swap-on" />
|
||||||
</button>
|
</button>
|
||||||
@@ -32,9 +32,11 @@ defineExpose({
|
|||||||
|
|
||||||
useEventListener(panel, "close", () => (open.value = false));
|
useEventListener(panel, "close", () => (open.value = false));
|
||||||
</script>
|
</script>
|
||||||
<style scoped lang="postcss">
|
<style scoped>
|
||||||
|
@import "@/main.css" reference;
|
||||||
|
|
||||||
.modal-right :where(.modal-box) {
|
.modal-right :where(.modal-box) {
|
||||||
@apply fixed right-0 h-lvh max-h-screen translate-x-24 scale-100 rounded-none bg-base-lighter shadow-none;
|
@apply bg-base-100 fixed right-0 h-lvh max-h-screen translate-x-24 scale-100 rounded-none shadow-none;
|
||||||
|
|
||||||
&[width="md"] {
|
&[width="md"] {
|
||||||
@apply max-w-3xl;
|
@apply max-w-3xl;
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
const { slideRight } = defineProps<{ slideRight: boolean }>();
|
const { slideRight } = defineProps<{ slideRight: boolean }>();
|
||||||
</script>
|
</script>
|
||||||
<style scoped lang="postcss">
|
<style scoped>
|
||||||
.slide-left-enter-active,
|
.slide-left-enter-active,
|
||||||
.slide-left-leave-active,
|
.slide-left-leave-active,
|
||||||
.slide-right-enter-active,
|
.slide-right-enter-active,
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="tag inline-flex items-center justify-center rounded bg-base-lighter px-2 py-[0.2em]" :size="size">
|
<div
|
||||||
|
class="tag bg-base-100 inline-flex items-center justify-center rounded-sm px-2 py-[0.2em] [[size='small']]:text-[0.8rem]"
|
||||||
|
:size="size"
|
||||||
|
>
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -7,9 +10,3 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
const { size = undefined } = defineProps<{ size?: "small" | undefined }>();
|
const { size = undefined } = defineProps<{ size?: "small" | undefined }>();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="postcss">
|
|
||||||
[size="small"] {
|
|
||||||
@apply text-xs;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|||||||
@@ -40,4 +40,4 @@ const cancel = () => {
|
|||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="postcss"></style>
|
<style scoped></style>
|
||||||
|
|||||||
@@ -25,8 +25,8 @@
|
|||||||
</pane>
|
</pane>
|
||||||
</splitpanes>
|
</splitpanes>
|
||||||
<label
|
<label
|
||||||
class="btn btn-circle swap btn-neutral swap-rotate fixed -left-12 bottom-4 w-16 transition-all hover:-left-4"
|
class="btn btn-circle swap bg-base-100 swap-rotate fixed bottom-4 -left-12 w-16 transition-all hover:-left-4"
|
||||||
:class="{ '!-left-6': collapseNav }"
|
:class="{ '-left-6!': collapseNav }"
|
||||||
v-if="!isMobile && !forceMenuHidden"
|
v-if="!isMobile && !forceMenuHidden"
|
||||||
>
|
>
|
||||||
<input type="checkbox" v-model="collapseNav" />
|
<input type="checkbox" v-model="collapseNav" />
|
||||||
@@ -34,7 +34,7 @@
|
|||||||
<mdi:chevron-left class="swap-off" />
|
<mdi:chevron-left class="swap-off" />
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<dialog ref="modal" class="modal items-start bg-white/20 backdrop:backdrop-blur-sm" @close="open = false">
|
<dialog ref="modal" class="modal items-start bg-white/20 backdrop:backdrop-blur-xs" @close="open = false">
|
||||||
<div class="modal-box max-w-2xl bg-transparent pt-20 shadow-none">
|
<div class="modal-box max-w-2xl bg-transparent pt-20 shadow-none">
|
||||||
<FuzzySearchModal @close="open = false" v-if="open" />
|
<FuzzySearchModal @close="open = false" v-if="open" />
|
||||||
</div>
|
</div>
|
||||||
@@ -117,9 +117,11 @@ function onResized(e: any) {
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="postcss">
|
<style scoped>
|
||||||
|
@import "@/main.css" reference;
|
||||||
|
|
||||||
:deep(.splitpanes--vertical > .splitpanes__splitter) {
|
:deep(.splitpanes--vertical > .splitpanes__splitter) {
|
||||||
@apply min-w-[3px] bg-base-lighter hover:bg-secondary;
|
@apply bg-base-100 hover:bg-secondary min-w-[3px];
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 768px) {
|
@media screen and (max-width: 768px) {
|
||||||
|
|||||||
226
assets/main.css
@@ -1,110 +1,134 @@
|
|||||||
@import "splitpanes/dist/splitpanes.css";
|
@import "tailwindcss";
|
||||||
|
@import "splitpanes/dist/splitpanes.css" layer(base);
|
||||||
|
@plugin "daisyui";
|
||||||
|
@plugin "@tailwindcss/typography";
|
||||||
|
|
||||||
@tailwind base;
|
@theme {
|
||||||
@tailwind components;
|
--color-green: oklch(69% 0.119722 188.479048);
|
||||||
@tailwind utilities;
|
--color-red: oklch(64% 0.218 28.85);
|
||||||
|
--color-purple: oklch(51.49% 0.215 321.03);
|
||||||
|
--color-blue: oklch(65% 0.171 249.5);
|
||||||
|
--color-orange: oklch(70% 0.186 48.13);
|
||||||
|
}
|
||||||
|
|
||||||
|
@plugin "daisyui/theme" {
|
||||||
|
name: "dark";
|
||||||
|
default: false;
|
||||||
|
prefersdark: false;
|
||||||
|
color-scheme: dark;
|
||||||
|
|
||||||
|
--color-base-100: oklch(25% 0 0);
|
||||||
|
--color-base-200: oklch(18% 0 0);
|
||||||
|
--color-base-300: oklch(11% 0 0);
|
||||||
|
--color-base-content: oklch(89.23% 0 0);
|
||||||
|
--color-primary: oklch(70.96% 0.143 176.65);
|
||||||
|
--color-primary-content: oklch(98% 0.01 240);
|
||||||
|
--color-secondary: oklch(81.38% 0.1448 90.1243);
|
||||||
|
--color-secondary-content: oklch(98% 0.01 200);
|
||||||
|
|
||||||
|
--color-neutral: oklch(50% 0.05 240);
|
||||||
|
--color-neutral-content: oklch(98% 0.01 240);
|
||||||
|
|
||||||
|
--color-info: var(--color-blue);
|
||||||
|
--color-info-content: oklch(98% 0.01 220);
|
||||||
|
|
||||||
|
--color-success: var(--color-green);
|
||||||
|
--color-success-content: oklch(98% 0.01 140);
|
||||||
|
|
||||||
|
--color-warning: var(--color-orange);
|
||||||
|
--color-success-content: oklch(98% 0.01 140);
|
||||||
|
|
||||||
|
--color-error: var(--color-red);
|
||||||
|
--color-error-content: oklch(98% 0.01 30);
|
||||||
|
|
||||||
|
--radius-selector: 1rem;
|
||||||
|
--radius-field: 0.25rem;
|
||||||
|
--radius-box: 0.5rem;
|
||||||
|
|
||||||
|
--border: 1px;
|
||||||
|
|
||||||
|
--depth: 0;
|
||||||
|
--noise: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@plugin "daisyui/theme" {
|
||||||
|
name: "light";
|
||||||
|
default: false;
|
||||||
|
prefersdark: false;
|
||||||
|
color-scheme: light;
|
||||||
|
|
||||||
|
--color-base-100: oklch(100% 0 0);
|
||||||
|
--color-base-200: oklch(97% 0 0);
|
||||||
|
--color-base-300: oklch(90% 0 0);
|
||||||
|
--color-base-content: oklch(33% 0 0);
|
||||||
|
--color-primary: oklch(79.96% 0.143 176.65);
|
||||||
|
--color-primary-content: oklch(98% 0.01 240);
|
||||||
|
--color-secondary: oklch(82.67% 0.15380739746702807 77.82);
|
||||||
|
--color-secondary-content: oklch(98% 0.01 200);
|
||||||
|
|
||||||
|
--color-neutral: oklch(50% 0.05 240);
|
||||||
|
--color-neutral-content: oklch(98% 0.01 240);
|
||||||
|
|
||||||
|
--color-info: var(--color-blue);
|
||||||
|
--color-info-content: oklch(98% 0.01 220);
|
||||||
|
|
||||||
|
--color-success: var(--color-green);
|
||||||
|
--color-success-content: oklch(98% 0.01 140);
|
||||||
|
|
||||||
|
--color-warning: var(--color-orange);
|
||||||
|
--color-success-content: oklch(98% 0.01 140);
|
||||||
|
|
||||||
|
--color-error: var(--color-red);
|
||||||
|
--color-error-content: oklch(98% 0.01 30);
|
||||||
|
|
||||||
|
--radius-selector: 1rem;
|
||||||
|
--radius-field: 0.25rem;
|
||||||
|
--radius-box: 0.5rem;
|
||||||
|
|
||||||
|
--border: 1px;
|
||||||
|
|
||||||
|
--depth: 0;
|
||||||
|
--noise: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@utility input {
|
||||||
|
@apply outline-hidden!;
|
||||||
|
&.input-ghost {
|
||||||
|
@apply focus:border-transparent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@utility btn {
|
||||||
|
&:not(.btn-primary):not(.btn-secondary) {
|
||||||
|
@apply hover:bg-base-100;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@utility mobile-hidden {
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@utility menu-active {
|
||||||
|
&,
|
||||||
|
&:active {
|
||||||
|
--color-neutral: var(--color-primary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@utility animate-bounce-fast {
|
||||||
|
animation: bounce 0.5s 2 both;
|
||||||
|
}
|
||||||
|
|
||||||
|
@utility link-primary {
|
||||||
|
@apply underline-offset-4 hover:underline;
|
||||||
|
}
|
||||||
|
|
||||||
@layer base {
|
@layer base {
|
||||||
:root {
|
|
||||||
--p: var(--primary-color);
|
|
||||||
--pc: 89.23% 0;
|
|
||||||
--s: var(--secondary-color);
|
|
||||||
--sc: 14.57% 0 0;
|
|
||||||
--b1: var(--base-lighter-color);
|
|
||||||
--b2: var(--base-color);
|
|
||||||
--b3: var(--base-darker-color);
|
|
||||||
--bc: var(--base-content-color);
|
|
||||||
--in: 65% 0.171 249.5;
|
|
||||||
--inc: 100% 0 0;
|
|
||||||
--er: 64% 0.218 28.85;
|
|
||||||
--su: 56% 0.119722 164.12;
|
|
||||||
--erc: 100% 0 0;
|
|
||||||
--wa: 70% 0.186 48.13;
|
|
||||||
--wac: 100% 0 0;
|
|
||||||
--n: var(--base-lighter-color);
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] {
|
|
||||||
--base-lighter-color: 25% 0 0;
|
|
||||||
--base-color: 18% 0 0;
|
|
||||||
--base-darker-color: 11% 0 0;
|
|
||||||
--base-content-color: 89.23% 0 0;
|
|
||||||
--primary-color: 70.96% 0.143 176.65;
|
|
||||||
--secondary-color: 81.38% 0.1448 90.1243;
|
|
||||||
}
|
|
||||||
|
|
||||||
html[data-theme="light"] {
|
|
||||||
--base-lighter-color: 100% 0 0;
|
|
||||||
--base-color: 97% 0 0;
|
|
||||||
--base-darker-color: 90% 0 0;
|
|
||||||
--base-content-color: 33% 0 0;
|
|
||||||
--primary-color: 79.96% 0.143 176.65;
|
|
||||||
--secondary-color: 82.67% 0.15380739746702807 77.82;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (max-device-width: 480px) {
|
@media screen and (max-device-width: 480px) {
|
||||||
body {
|
body {
|
||||||
-webkit-text-size-adjust: 100%;
|
-webkit-text-size-adjust: 100%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
h1 {
|
|
||||||
@apply text-3xl;
|
|
||||||
}
|
|
||||||
|
|
||||||
h2 {
|
|
||||||
@apply text-2xl;
|
|
||||||
}
|
|
||||||
|
|
||||||
h3 {
|
|
||||||
@apply text-lg;
|
|
||||||
}
|
|
||||||
|
|
||||||
.events 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 !outline-none;
|
|
||||||
&.input-ghost {
|
|
||||||
@apply focus:border-transparent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn {
|
|
||||||
@apply font-normal normal-case;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn:not(.btn-primary):not(.btn-secondary) {
|
|
||||||
@apply hover:bg-base-lighter;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@layer utilities {
|
|
||||||
@media (max-width: 768px) {
|
|
||||||
.mobile-hidden {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.active-primary {
|
|
||||||
--n: var(--p);
|
|
||||||
--nc: var(--pc);
|
|
||||||
@apply active;
|
|
||||||
}
|
|
||||||
|
|
||||||
.link-primary {
|
|
||||||
@apply underline-offset-4 hover:underline;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<PageWithLinks>
|
<PageWithLinks>
|
||||||
<div class="hero min-h-screen bg-base-200">
|
<div class="hero bg-base-200 min-h-screen">
|
||||||
<div class="hero-content text-center">
|
<div class="hero-content text-center">
|
||||||
<div class="max-w-md">
|
<div class="max-w-md">
|
||||||
<p class="py-6 text-2xl font-bold">{{ $t("error.page-not-found") }}</p>
|
<p class="py-6 text-2xl font-bold">{{ $t("error.page-not-found") }}</p>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<Search />
|
<Search />
|
||||||
<ContainerLog :id="id" :show-title="true" :scrollable="pinnedLogs.length > 0" v-if="currentContainer" />
|
<ContainerLog :id="id" :show-title="true" :scrollable="pinnedLogs.length > 0" v-if="currentContainer" />
|
||||||
<div v-else-if="ready" class="hero min-h-screen bg-base-200">
|
<div v-else-if="ready" class="hero bg-base-200 min-h-screen">
|
||||||
<div class="hero-content text-center">
|
<div class="hero-content text-center">
|
||||||
<div class="max-w-md">
|
<div class="max-w-md">
|
||||||
<p class="py-6 text-2xl font-bold">{{ $t("error.container-not-found") }}</p>
|
<p class="py-6 text-2xl font-bold">{{ $t("error.container-not-found") }}</p>
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ watchEffect(() => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
<style lang="postcss" scoped>
|
<style scoped>
|
||||||
:deep(tr td) {
|
:deep(tr td) {
|
||||||
padding-top: 1em;
|
padding-top: 1em;
|
||||||
padding-bottom: 1em;
|
padding-bottom: 1em;
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="card w-96 shrink-0 bg-base-lighter shadow-2xl">
|
<div class="card bg-base-100 w-96 shrink-0 shadow-2xl">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<form action="" method="post" @submit.prevent="onLogin" ref="form" class="flex flex-col gap-8">
|
<form action="" method="post" @submit.prevent="onLogin" ref="form" class="flex flex-col gap-8">
|
||||||
<label class="form-control w-full">
|
<label class="form-control w-full">
|
||||||
<label
|
<label
|
||||||
class="input input-bordered flex items-center gap-2 border-2 has-[:focus]:input-primary"
|
class="input floating-label input-bordered has-[:focus]:input-primary flex items-center gap-2 border-2"
|
||||||
:class="{ 'input-error': error }"
|
:class="{ 'input-error': error }"
|
||||||
>
|
>
|
||||||
|
<span class="ml-5">{{ $t("label.username") }}</span>
|
||||||
<mdi:account class="has-[+:focus]:text-primary" :class="{ 'text-error': error }" />
|
<mdi:account class="has-[+:focus]:text-primary" :class="{ 'text-error': error }" />
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
class="grow"
|
|
||||||
:class="{ 'text-error': error }"
|
:class="{ 'text-error': error }"
|
||||||
:placeholder="$t('label.username')"
|
:placeholder="$t('label.username')"
|
||||||
name="username"
|
name="username"
|
||||||
@@ -27,11 +27,13 @@
|
|||||||
</label>
|
</label>
|
||||||
</label>
|
</label>
|
||||||
<label class="form-control w-full">
|
<label class="form-control w-full">
|
||||||
<label class="input input-bordered flex items-center gap-2 border-2 has-[:focus]:input-primary">
|
<label
|
||||||
|
class="input floating-label input-bordered has-[:focus]:input-primary flex items-center gap-2 border-2"
|
||||||
|
>
|
||||||
|
<span class="ml-5">{{ $t("label.password") }}</span>
|
||||||
<mdi:key class="has-[+:focus]:text-primary" />
|
<mdi:key class="has-[+:focus]:text-primary" />
|
||||||
<input
|
<input
|
||||||
type="password"
|
type="password"
|
||||||
class="grow"
|
|
||||||
:placeholder="$t('label.password')"
|
:placeholder="$t('label.password')"
|
||||||
name="password"
|
name="password"
|
||||||
autocomplete="current-password"
|
autocomplete="current-password"
|
||||||
|
|||||||
@@ -14,13 +14,13 @@
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="flex flex-col @container">
|
<section class="@container flex flex-col">
|
||||||
<div class="has-underline">
|
<div class="has-underline">
|
||||||
<h2>{{ $t("settings.display") }}</h2>
|
<h2>{{ $t("settings.display") }}</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<section class="grid-cols-2 gap-4 @3xl:grid">
|
<section class="grid-cols-2 gap-4 @3xl:grid">
|
||||||
<div class="flex flex-col gap-2 text-balance @3xl:pr-8">
|
<div class="flex flex-col gap-4 text-balance @3xl:pr-8">
|
||||||
<Toggle v-model="compact"> {{ $t("settings.compact") }} </Toggle>
|
<Toggle v-model="compact"> {{ $t("settings.compact") }} </Toggle>
|
||||||
|
|
||||||
<Toggle v-model="smallerScrollbars"> {{ $t("settings.small-scrollbars") }} </Toggle>
|
<Toggle v-model="smallerScrollbars"> {{ $t("settings.small-scrollbars") }} </Toggle>
|
||||||
@@ -51,7 +51,7 @@
|
|||||||
{{ $t("settings.datetime-format") }}
|
{{ $t("settings.datetime-format") }}
|
||||||
</template>
|
</template>
|
||||||
<template #input>
|
<template #input>
|
||||||
<div class="flex gap-2">
|
<div class="flex gap-4">
|
||||||
<DropdownMenu
|
<DropdownMenu
|
||||||
v-model="dateLocale"
|
v-model="dateLocale"
|
||||||
:options="[
|
:options="[
|
||||||
@@ -110,28 +110,22 @@
|
|||||||
:messages="fakeMessages"
|
:messages="fakeMessages"
|
||||||
:last-selected-item="undefined"
|
:last-selected-item="undefined"
|
||||||
:show-container-name="false"
|
:show-container-name="false"
|
||||||
class="hidden overflow-hidden rounded-lg border border-base-content/50 shadow @3xl:block"
|
class="border-base-content/50 hidden overflow-hidden rounded-lg border shadow-sm @3xl:block"
|
||||||
/>
|
/>
|
||||||
</section>
|
</section>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="flex flex-col gap-2">
|
<section class="flex flex-col gap-4">
|
||||||
<div class="has-underline">
|
<div class="has-underline">
|
||||||
<h2>{{ $t("settings.options") }}</h2>
|
<h2>{{ $t("settings.options") }}</h2>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<Toggle v-model="search">
|
||||||
<toggle v-model="search">
|
{{ $t("settings.search") }} <key-shortcut char="f" class="align-top"></key-shortcut>
|
||||||
{{ $t("settings.search") }} <key-shortcut char="f" class="align-top"></key-shortcut>
|
</Toggle>
|
||||||
</toggle>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
<Toggle v-model="showAllContainers">{{ $t("settings.show-stopped-containers") }}</Toggle>
|
||||||
<toggle v-model="showAllContainers">{{ $t("settings.show-stopped-containers") }}</toggle>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
<Toggle v-model="automaticRedirect">{{ $t("settings.automatic-redirect") }}</Toggle>
|
||||||
<toggle v-model="automaticRedirect">{{ $t("settings.automatic-redirect") }}</toggle>
|
|
||||||
</div>
|
|
||||||
</section>
|
</section>
|
||||||
</PageWithLinks>
|
</PageWithLinks>
|
||||||
</template>
|
</template>
|
||||||
@@ -211,9 +205,15 @@ const fakeMessages = computedWithControl(
|
|||||||
],
|
],
|
||||||
);
|
);
|
||||||
</script>
|
</script>
|
||||||
<style lang="postcss" scoped>
|
<style scoped>
|
||||||
|
@import "@/main.css" reference;
|
||||||
|
|
||||||
.has-underline {
|
.has-underline {
|
||||||
@apply mb-4 border-b border-base-content/50 py-4;
|
@apply border-base-content/50 mb-4 border-b py-4;
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
@apply text-2xl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(a:not(.menu a)) {
|
:deep(a:not(.menu a)) {
|
||||||
|
|||||||
@@ -1,18 +1,13 @@
|
|||||||
<script setup>
|
|
||||||
import { data } from "../../activity.data.ts";
|
|
||||||
import Counter from "./Counter.vue";
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="stats mt-10">
|
<div class="stats mt-10">
|
||||||
<div class="stat w-40">
|
<div class="stat w-40 border-0!">
|
||||||
<div class="stat-title">Github Stars</div>
|
<div class="stat-title">Github Stars</div>
|
||||||
<div class="stat-value">
|
<div class="stat-value">
|
||||||
<Counter :start="0" :end="data.stars" :duration="1000" :formatter="(value) => (value / 1e3).toFixed(1) + 'K'" />
|
<Counter :start="0" :end="data.stars" :duration="1000" :formatter="(value) => (value / 1e3).toFixed(1) + 'K'" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="stat !border-l-0">
|
<div class="stat">
|
||||||
<div class="stat-title">Docker Pulls</div>
|
<div class="stat-title">Docker Pulls</div>
|
||||||
<div class="stat-value">
|
<div class="stat-value">
|
||||||
<Counter :start="0" :end="data.pulls" :duration="1000" :formatter="(value) => (value / 1e6).toFixed(0) + 'M'" />
|
<Counter :start="0" :end="data.pulls" :duration="1000" :formatter="(value) => (value / 1e6).toFixed(0) + 'M'" />
|
||||||
@@ -20,3 +15,7 @@ import Counter from "./Counter.vue";
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { data } from "../../activity.data";
|
||||||
|
import Counter from "./Counter.vue";
|
||||||
|
</script>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
@tailwind base;
|
@import "tailwindcss";
|
||||||
@tailwind components;
|
@plugin "daisyui" {
|
||||||
@tailwind utilities;
|
include: stat;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Customize default theme styling by overriding CSS variables:
|
* Customize default theme styling by overriding CSS variables:
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
plugins: {
|
|
||||||
tailwindcss: { config: "./docs/tailwind.docs.ts" },
|
|
||||||
autoprefixer: {},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
import type { Config } from "tailwindcss";
|
|
||||||
import DaisyUI from "daisyui";
|
|
||||||
|
|
||||||
export default {
|
|
||||||
future: {
|
|
||||||
hoverOnlyWhenSupported: true,
|
|
||||||
},
|
|
||||||
darkMode: "selector",
|
|
||||||
content: ["docs/.vitepress/theme/**/*.{vue,js,ts}"],
|
|
||||||
plugins: [DaisyUI],
|
|
||||||
daisyui: {
|
|
||||||
themes: [],
|
|
||||||
base: false,
|
|
||||||
logs: false,
|
|
||||||
},
|
|
||||||
} satisfies Config;
|
|
||||||
@@ -1,10 +1,12 @@
|
|||||||
import path from "path";
|
import path from "path";
|
||||||
|
import tailwindcss from "@tailwindcss/vite";
|
||||||
import { defineConfig } from "vite";
|
import { defineConfig } from "vite";
|
||||||
|
|
||||||
import Components from "unplugin-vue-components/vite";
|
import Components from "unplugin-vue-components/vite";
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [
|
plugins: [
|
||||||
|
tailwindcss(),
|
||||||
Components({
|
Components({
|
||||||
dirs: [path.resolve(__dirname, ".vitepress/theme/components")],
|
dirs: [path.resolve(__dirname, ".vitepress/theme/components")],
|
||||||
extensions: ["vue", "md"],
|
extensions: ["vue", "md"],
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
@@ -39,31 +39,29 @@
|
|||||||
"@iconify-json/octicon": "^1.2.2",
|
"@iconify-json/octicon": "^1.2.2",
|
||||||
"@iconify-json/ph": "^1.2.2",
|
"@iconify-json/ph": "^1.2.2",
|
||||||
"@intlify/unplugin-vue-i18n": "^6.0.3",
|
"@intlify/unplugin-vue-i18n": "^6.0.3",
|
||||||
"@tailwindcss/container-queries": "^0.1.1",
|
|
||||||
"@tailwindcss/typography": "^0.5.15",
|
"@tailwindcss/typography": "^0.5.15",
|
||||||
|
"@tailwindcss/vite": "4.0.0-beta.8",
|
||||||
"@vueuse/components": "^12.3.0",
|
"@vueuse/components": "^12.3.0",
|
||||||
"@vueuse/core": "^12.3.0",
|
"@vueuse/core": "^12.3.0",
|
||||||
"@vueuse/integrations": "^12.3.0",
|
"@vueuse/integrations": "^12.3.0",
|
||||||
"@vueuse/router": "^12.3.0",
|
"@vueuse/router": "^12.3.0",
|
||||||
"ansi-to-html": "^0.7.2",
|
"ansi-to-html": "^0.7.2",
|
||||||
"autoprefixer": "^10.4.20",
|
|
||||||
"d3-array": "^3.2.4",
|
"d3-array": "^3.2.4",
|
||||||
"d3-ease": "^3.0.1",
|
"d3-ease": "^3.0.1",
|
||||||
"d3-scale": "^4.0.2",
|
"d3-scale": "^4.0.2",
|
||||||
"d3-selection": "^3.0.0",
|
"d3-selection": "^3.0.0",
|
||||||
"d3-shape": "^3.2.0",
|
"d3-shape": "^3.2.0",
|
||||||
"d3-transition": "^3.0.1",
|
"d3-transition": "^3.0.1",
|
||||||
"daisyui": "^4.12.23",
|
"daisyui": "5.0.0-beta.1",
|
||||||
"date-fns": "^4.1.0",
|
"date-fns": "^4.1.0",
|
||||||
"entities": "^6.0.0",
|
"entities": "^6.0.0",
|
||||||
"fuse.js": "^7.0.0",
|
"fuse.js": "^7.0.0",
|
||||||
"lodash.debounce": "^4.0.8",
|
"lodash.debounce": "^4.0.8",
|
||||||
"pinia": "^2.3.0",
|
"pinia": "^2.3.0",
|
||||||
"postcss": "^8.4.49",
|
|
||||||
"sortablejs": "^1.15.6",
|
"sortablejs": "^1.15.6",
|
||||||
"splitpanes": "^3.1.5",
|
"splitpanes": "^3.1.5",
|
||||||
"strip-ansi": "^7.1.0",
|
"strip-ansi": "^7.1.0",
|
||||||
"tailwindcss": "^3.4.17",
|
"tailwindcss": "4.0.0-beta.8",
|
||||||
"unplugin-auto-import": "^0.19.0",
|
"unplugin-auto-import": "^0.19.0",
|
||||||
"unplugin-icons": "^0.22.0",
|
"unplugin-icons": "^0.22.0",
|
||||||
"unplugin-vue-components": "^0.28.0",
|
"unplugin-vue-components": "^0.28.0",
|
||||||
|
|||||||
760
pnpm-lock.yaml
generated
@@ -1,7 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
plugins: {
|
|
||||||
"tailwindcss/nesting": {},
|
|
||||||
tailwindcss: {},
|
|
||||||
autoprefixer: {},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html class="bg-base text-base-content">
|
<html class="bg-base-200 text-base-content">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
|||||||
@@ -1,43 +0,0 @@
|
|||||||
import type { Config } from "tailwindcss";
|
|
||||||
import DaisyUI from "daisyui";
|
|
||||||
import Typography from "@tailwindcss/typography";
|
|
||||||
import Container from "@tailwindcss/container-queries";
|
|
||||||
|
|
||||||
export default {
|
|
||||||
future: {
|
|
||||||
hoverOnlyWhenSupported: true,
|
|
||||||
},
|
|
||||||
content: ["./assets/**/*.{vue,js,ts}", "./public/index.html"],
|
|
||||||
theme: {
|
|
||||||
extend: {
|
|
||||||
blur: {
|
|
||||||
xs: "1px",
|
|
||||||
},
|
|
||||||
animation: {
|
|
||||||
"bounce-fast": "bounce 0.5s 2 both",
|
|
||||||
},
|
|
||||||
backgroundImage: {
|
|
||||||
"gradient-radial": "radial-gradient(var(--tw-gradient-stops))",
|
|
||||||
},
|
|
||||||
colors: {
|
|
||||||
green: "oklch(69% 0.119722 188.479048)",
|
|
||||||
red: "oklch(64% 0.218 28.85)",
|
|
||||||
purple: "oklch(51.49% 0.215 321.03)",
|
|
||||||
blue: "oklch(65% 0.171 249.5)",
|
|
||||||
orange: "oklch(70% 0.186 48.13)",
|
|
||||||
base: "oklch(var(--base-color) / <alpha-value>)",
|
|
||||||
"base-darker": "oklch(var(--base-darker-color) / <alpha-value>)",
|
|
||||||
"base-lighter": "oklch(var(--base-lighter-color) / <alpha-value>)",
|
|
||||||
"base-content": "oklch(var(--base-content-color) / <alpha-value>)",
|
|
||||||
primary: "oklch(var(--primary-color) / <alpha-value>)",
|
|
||||||
secondary: "oklch(var(--secondary-color) / <alpha-value>)",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
plugins: [DaisyUI, Typography, Container],
|
|
||||||
daisyui: {
|
|
||||||
themes: [],
|
|
||||||
base: false,
|
|
||||||
logs: false,
|
|
||||||
},
|
|
||||||
} satisfies Config;
|
|
||||||
@@ -12,6 +12,7 @@ import VueI18nPlugin from "@intlify/unplugin-vue-i18n/vite";
|
|||||||
import { compression } from "vite-plugin-compression2";
|
import { compression } from "vite-plugin-compression2";
|
||||||
import { VueRouterAutoImports } from "unplugin-vue-router";
|
import { VueRouterAutoImports } from "unplugin-vue-router";
|
||||||
import svgLoader from "vite-svg-loader";
|
import svgLoader from "vite-svg-loader";
|
||||||
|
import tailwindcss from "@tailwindcss/vite";
|
||||||
|
|
||||||
export default defineConfig(() => ({
|
export default defineConfig(() => ({
|
||||||
resolve: {
|
resolve: {
|
||||||
@@ -73,6 +74,7 @@ export default defineConfig(() => ({
|
|||||||
}),
|
}),
|
||||||
compression({ algorithm: "brotliCompress", exclude: [/\.(html)$/] }),
|
compression({ algorithm: "brotliCompress", exclude: [/\.(html)$/] }),
|
||||||
svgLoader({}),
|
svgLoader({}),
|
||||||
|
tailwindcss(),
|
||||||
],
|
],
|
||||||
test: {
|
test: {
|
||||||
include: ["assets/**/*.spec.ts"],
|
include: ["assets/**/*.spec.ts"],
|
||||||
|
|||||||