chore: upgrades to tailwind v4 and daisyUI v5 🎨 (#3505)
@@ -18,7 +18,7 @@ watchEffect(() => {
|
||||
document.documentElement.setAttribute("data-theme", theme);
|
||||
});
|
||||
</script>
|
||||
<style lang="postcss">
|
||||
<style>
|
||||
html.has-custom-scrollbars {
|
||||
::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
type="radio"
|
||||
name="host"
|
||||
role="tab"
|
||||
class="tab !rounded"
|
||||
class="tab rounded-sm!"
|
||||
aria-label="Show All"
|
||||
v-model="selectedHost"
|
||||
:value="null"
|
||||
@@ -16,7 +16,7 @@
|
||||
type="radio"
|
||||
name="host"
|
||||
role="tab"
|
||||
class="tab !rounded"
|
||||
class="tab rounded-sm!"
|
||||
:aria-label="host.name"
|
||||
v-for="host in hosts"
|
||||
:value="host.id"
|
||||
@@ -46,7 +46,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<table class="table table-lg bg-base">
|
||||
<table class="table-lg bg-base-200 table">
|
||||
<thead>
|
||||
<tr :data-direction="direction > 0 ? 'asc' : 'desc'">
|
||||
<th
|
||||
@@ -196,7 +196,9 @@ function isVisible(field: keys) {
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="postcss" scoped>
|
||||
<style scoped>
|
||||
@import "@/main.css" reference;
|
||||
|
||||
[data-icon] {
|
||||
display: none;
|
||||
transition: transform 0.2s ease-in-out;
|
||||
@@ -206,7 +208,7 @@ function isVisible(field: keys) {
|
||||
}
|
||||
|
||||
th {
|
||||
@apply border-b-2 border-base-lighter;
|
||||
@apply border-base-100 border-b-2;
|
||||
&.selected-sort {
|
||||
font-weight: bold;
|
||||
@apply border-primary;
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<template>
|
||||
<div class="dropdown dropdown-end dropdown-hover">
|
||||
<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="w-2.5 text-blue" v-if="streamConfig.stdout" />
|
||||
<carbon:circle-solid class="text-red w-2.5" v-if="streamConfig.stderr" />
|
||||
<carbon:circle-solid class="text-blue w-2.5" v-if="streamConfig.stdout" />
|
||||
</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>
|
||||
<a @click.prevent="clear()">
|
||||
<octicon:trash-24 /> {{ $t("toolbar.clear") }}
|
||||
@@ -31,8 +31,8 @@
|
||||
<details>
|
||||
<summary>
|
||||
<div class="flex w-4">
|
||||
<carbon:circle-solid class="w-2.5 text-red" v-if="streamConfig.stderr" />
|
||||
<carbon:circle-solid class="w-2.5 text-blue" v-if="streamConfig.stdout" />
|
||||
<carbon:circle-solid class="text-red w-2.5" v-if="streamConfig.stderr" />
|
||||
<carbon:circle-solid class="text-blue w-2.5" v-if="streamConfig.stdout" />
|
||||
</div>
|
||||
Streams
|
||||
</summary>
|
||||
@@ -187,9 +187,11 @@ const toggleAllLevels = computed({
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="postcss">
|
||||
<style scoped>
|
||||
@import "@/main.css" reference;
|
||||
|
||||
li.line {
|
||||
@apply h-px bg-base-content/20;
|
||||
@apply bg-base-content/20 h-px;
|
||||
}
|
||||
|
||||
a {
|
||||
|
||||
@@ -14,7 +14,8 @@ defineProps<{
|
||||
}>();
|
||||
</script>
|
||||
|
||||
<style lang="postcss" scoped>
|
||||
<style scoped>
|
||||
@import "@/main.css" reference;
|
||||
[health="unhealthy"] {
|
||||
@apply text-red;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<ScrollableView :scrollable="scrollable" v-if="container">
|
||||
<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" />
|
||||
<MultiContainerStat class="ml-auto lg:hidden lg:@3xl:flex" :containers="[container]" />
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<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">
|
||||
<input type="checkbox" v-model="pinned" />
|
||||
<carbon:star-filled class="swap-on text-secondary" />
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<template>
|
||||
<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" />
|
||||
<input
|
||||
tabindex="0"
|
||||
class="input input-lg input-ghost flex-1 px-1"
|
||||
class="input-ghost flex-1 px-1"
|
||||
ref="input"
|
||||
@keydown.down="selectedIndex = Math.min(selectedIndex + 1, data.length - 1)"
|
||||
@keydown.up="selectedIndex = Math.max(selectedIndex - 1, 0)"
|
||||
@@ -21,15 +21,15 @@
|
||||
</form>
|
||||
</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"
|
||||
>
|
||||
<ul tabindex="0" class="menu">
|
||||
<ul tabindex="0" class="menu w-auto">
|
||||
<li v-for="(result, index) in data" ref="listItems">
|
||||
<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)"
|
||||
:class="index === selectedIndex ? 'focus' : ''"
|
||||
:class="index === selectedIndex ? 'menu-focus' : ''"
|
||||
>
|
||||
<div :class="{ 'text-primary': result.item.state === 'running' }">
|
||||
<template v-if="result.item.type === 'container'">
|
||||
@@ -85,6 +85,15 @@ const { visibleContainers } = storeToRefs(containerStore);
|
||||
const swarmStore = useSwarmStore();
|
||||
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 = {
|
||||
id: string;
|
||||
created: Date;
|
||||
@@ -167,8 +176,6 @@ watch(selectedIndex, () => {
|
||||
listItems.value?.[selectedIndex.value].scrollIntoView({ block: "end" });
|
||||
});
|
||||
|
||||
useFocus(input, { initialValue: true });
|
||||
|
||||
function selected(item: Item) {
|
||||
if (item.type === "container") {
|
||||
router.push({ name: "/container/[id]", params: { id: item.id } });
|
||||
@@ -204,7 +211,7 @@ function matchedName({ item, matches = [] }: FuseResult<Item>) {
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="postcss">
|
||||
<style scoped>
|
||||
:deep(mark) {
|
||||
@apply bg-transparent text-inherit underline underline-offset-2;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<ScrollableView :scrollable="scrollable" v-if="group.containers.length && ready">
|
||||
<template #header>
|
||||
<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="font-semibold">{{ $t("label.container", group.containers.length) }}</div>
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<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="flex flex-col gap-2 overflow-hidden">
|
||||
<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="radial-progress text-sm text-primary [--size:4rem] [--thickness:0.25em] md:text-[1rem] md:[--size:5rem]"
|
||||
:style="`--value: ${Math.floor((weightedStats[host.id].weighted.totalCPU / (host.nCPU * 100)) * 100)}; `"
|
||||
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)};`"
|
||||
role="progressbar"
|
||||
>
|
||||
{{ weightedStats[host.id].weighted.totalCPU.toFixed(0) }}%
|
||||
</div>
|
||||
<div
|
||||
class="radial-progress text-sm text-primary [--size:4rem] [--thickness:0.25em] md:text-[1rem] md:[--size:5rem]"
|
||||
:style="`--value: ${(weightedStats[host.id].weighted.totalMem / host.memTotal) * 100};`"
|
||||
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.totalMem / host.memTotal) * 100)};`"
|
||||
role="progressbar"
|
||||
>
|
||||
{{ formatBytes(weightedStats[host.id].weighted.totalMem, 1) }}
|
||||
@@ -114,5 +114,3 @@ useIntervalFn(
|
||||
{ immediate: true },
|
||||
);
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
<label tabindex="0" class="btn btn-square btn-ghost btn-sm">
|
||||
<ph:dots-three-vertical-bold />
|
||||
</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>
|
||||
<a class="text-sm capitalize" @click="toggleShowAllContainers()">
|
||||
<mdi:check class="w-4" v-if="showAllContainers" />
|
||||
@@ -44,7 +44,7 @@
|
||||
<template #left>
|
||||
<ul class="menu p-0">
|
||||
<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" />
|
||||
{{ host.name }}
|
||||
<span class="badge badge-error badge-xs p-1.5" v-if="!host.available">offline</span>
|
||||
@@ -53,10 +53,10 @@
|
||||
</ul>
|
||||
</template>
|
||||
<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">
|
||||
<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" />
|
||||
{{ label.startsWith("label.") ? $t(label) : label }}
|
||||
|
||||
@@ -77,7 +77,7 @@
|
||||
<Popup>
|
||||
<router-link
|
||||
:to="{ name: '/container/[id]', params: { id: item.id } }"
|
||||
active-class="active-primary"
|
||||
active-class="menu-active"
|
||||
@click.alt.stop.prevent="pinnedStore.pinContainer(item)"
|
||||
:title="item.name"
|
||||
class="group auto-cols-[auto_max-content_max-content]"
|
||||
@@ -87,7 +87,7 @@
|
||||
</div>
|
||||
<ContainerHealth :health="item.health" />
|
||||
<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)"
|
||||
v-show="!pinnedStore.isPinned(item)"
|
||||
:title="$t('tooltip.pin-column')"
|
||||
@@ -209,7 +209,7 @@ watchEffect(() => {
|
||||
|
||||
const toggleShowAllContainers = () => (showAllContainers.value = !showAllContainers.value);
|
||||
</script>
|
||||
<style scoped lang="postcss">
|
||||
<style scoped>
|
||||
.menu {
|
||||
@apply text-[0.95rem];
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<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>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<template #trigger>
|
||||
<mdi:announcement class="size-6 -rotate-12" />
|
||||
<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"
|
||||
></span>
|
||||
</template>
|
||||
@@ -28,7 +28,7 @@
|
||||
<dropdown class="dropdown-end" v-if="config.user">
|
||||
<template #trigger>
|
||||
<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')"
|
||||
/>
|
||||
</template>
|
||||
@@ -43,7 +43,7 @@
|
||||
</div>
|
||||
<ul class="menu mt-4 p-0">
|
||||
<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>
|
||||
</ul>
|
||||
</template>
|
||||
|
||||
@@ -29,7 +29,8 @@ const validValues = computed(() => {
|
||||
const showDrawer = useDrawer();
|
||||
</script>
|
||||
|
||||
<style lang="postcss" scoped>
|
||||
<style scoped>
|
||||
@import "@/main.css" reference;
|
||||
.text-light {
|
||||
@apply text-base-content/70;
|
||||
}
|
||||
|
||||
@@ -71,7 +71,8 @@ function redirectNow() {
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="postcss" scoped>
|
||||
<style scoped>
|
||||
@import "@/main.css" reference;
|
||||
[data-event="container-stopped"] {
|
||||
@apply text-red;
|
||||
}
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
<InfiniteLoader :onLoadMore="fetchMore" :enabled="!loadingMore && messages.length > 10" />
|
||||
<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="h-3 w-40 shrink-0 rounded-full bg-base-content/50 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 w-40 shrink-0 rounded-full opacity-50"></div>
|
||||
<div class="bg-base-content/50 h-3 rounded-full opacity-50" :class="size"></div>
|
||||
</div>
|
||||
<span class="sr-only">Loading...</span>
|
||||
</ul>
|
||||
|
||||
@@ -94,4 +94,4 @@ const page = computed(() =>
|
||||
results.value.numRows > pageLimit ? results.value.slice(0, pageLimit) : results.value,
|
||||
) as unknown as ComputedRef<Table<Record<string, any>>>;
|
||||
</script>
|
||||
<style lang="postcss" scoped></style>
|
||||
<style scoped></style>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<Tag size="small" class="!items-start">
|
||||
<DateTime :date="date" class="whitespace-nowrap text-blue" />
|
||||
<Tag size="small" class="items-start!">
|
||||
<DateTime :date="date" class="text-blue whitespace-nowrap" />
|
||||
</Tag>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<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">
|
||||
<DateTime :date="entry.date" />
|
||||
</h1>
|
||||
@@ -26,21 +26,21 @@
|
||||
</section>
|
||||
|
||||
<section class="flex flex-col gap-2">
|
||||
<div class="flex gap-2 font-thin">
|
||||
<div class="flex gap-2">
|
||||
Raw JSON
|
||||
|
||||
<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:content-copy class="swap-off" />
|
||||
</button>
|
||||
</UseClipboard>
|
||||
</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>
|
||||
</div>
|
||||
</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">
|
||||
Fields are sortable by dragging and dropping.
|
||||
</caption>
|
||||
@@ -55,7 +55,7 @@
|
||||
</thead>
|
||||
<tbody ref="list">
|
||||
<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(".") }}
|
||||
</td>
|
||||
<td class="mobile-hidden truncate">
|
||||
@@ -164,7 +164,8 @@ function syntaxHighlight(json: any) {
|
||||
|
||||
useSortable(list, fields);
|
||||
</script>
|
||||
<style lang="postcss" scoped>
|
||||
<style scoped>
|
||||
@import "@/main.css" reference;
|
||||
.font-mono {
|
||||
font-family:
|
||||
ui-monospace,
|
||||
@@ -178,19 +179,19 @@ useSortable(list, fields);
|
||||
}
|
||||
|
||||
pre {
|
||||
:deep(.json-key) {
|
||||
& :deep(.json-key) {
|
||||
@apply text-blue;
|
||||
}
|
||||
:deep(.json-string) {
|
||||
& :deep(.json-string) {
|
||||
@apply text-green;
|
||||
}
|
||||
:deep(.json-number) {
|
||||
& :deep(.json-number) {
|
||||
@apply text-orange;
|
||||
}
|
||||
:deep(.json-boolean) {
|
||||
& :deep(.json-boolean) {
|
||||
@apply text-purple;
|
||||
}
|
||||
:deep(.json-null) {
|
||||
& :deep(.json-null) {
|
||||
@apply text-red;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,8 @@ defineProps<{
|
||||
}>();
|
||||
</script>
|
||||
|
||||
<style lang="postcss" scoped>
|
||||
<style scoped>
|
||||
@import "@/main.css" reference;
|
||||
[data-position="start"] {
|
||||
border-radius: 0.5em 0.5em 0 0;
|
||||
height: 70%;
|
||||
@@ -33,7 +34,8 @@ defineProps<{
|
||||
align-self: flex-start;
|
||||
}
|
||||
</style>
|
||||
<style lang="postcss">
|
||||
<style>
|
||||
@import "@/main.css" reference;
|
||||
[data-level="debug"],
|
||||
[data-level="trace"] {
|
||||
@apply !bg-purple;
|
||||
|
||||
@@ -53,7 +53,8 @@ useIntersectionObserver(
|
||||
},
|
||||
);
|
||||
</script>
|
||||
<style scoped lang="postcss">
|
||||
<style scoped>
|
||||
@import "@/main.css" reference;
|
||||
.events {
|
||||
font-family:
|
||||
ui-monospace,
|
||||
@@ -66,7 +67,7 @@ useIntersectionObserver(
|
||||
monospace;
|
||||
|
||||
> 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 {
|
||||
scroll-margin-block-end: 5rem;
|
||||
}
|
||||
@@ -93,5 +94,19 @@ useIntersectionObserver(
|
||||
@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>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
:title="t('log_actions.copy_log')"
|
||||
>
|
||||
<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()"
|
||||
>
|
||||
<carbon:copy-file />
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<Tag size="small" :std="std" class="!items-start">
|
||||
<Tag size="small" :std="std" class="items-start!">
|
||||
{{ std }}
|
||||
</Tag>
|
||||
</template>
|
||||
@@ -12,7 +12,8 @@ defineProps<{
|
||||
}>();
|
||||
</script>
|
||||
|
||||
<style lang="postcss" scoped>
|
||||
<style scoped>
|
||||
@import "@/main.css" reference;
|
||||
[std="stdout"] {
|
||||
@apply text-blue;
|
||||
}
|
||||
|
||||
@@ -39,4 +39,4 @@ watchEffect(() => {
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<style scoped lang="postcss"></style>
|
||||
<style scoped></style>
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<template>
|
||||
<div class="dropdown dropdown-end dropdown-hover">
|
||||
<label tabindex="0" class="btn btn-ghost btn-sm gap-0.5 px-2">
|
||||
<carbon:circle-solid class="w-2.5 text-red" v-if="streamConfig.stderr" />
|
||||
<carbon:circle-solid class="w-2.5 text-blue" v-if="streamConfig.stdout" />
|
||||
<carbon:circle-solid class="text-red w-2.5" v-if="streamConfig.stderr" />
|
||||
<carbon:circle-solid class="text-blue w-2.5" v-if="streamConfig.stdout" />
|
||||
</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>
|
||||
<a @click.prevent="clear()">
|
||||
<octicon:trash-24 /> {{ $t("toolbar.clear") }}
|
||||
@@ -30,8 +30,8 @@
|
||||
>
|
||||
<div class="flex size-4 gap-0.5">
|
||||
<template v-if="streamConfig.stderr && streamConfig.stdout">
|
||||
<carbon:circle-solid class="w-2 text-red" />
|
||||
<carbon:circle-solid class="w-2 text-blue" />
|
||||
<carbon:circle-solid class="text-red w-2" />
|
||||
<carbon:circle-solid class="text-blue w-2" />
|
||||
</template>
|
||||
</div>
|
||||
{{ $t("toolbar.show-all") }}
|
||||
@@ -45,7 +45,7 @@
|
||||
"
|
||||
>
|
||||
<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>
|
||||
{{ $t("toolbar.show", { std: "STDOUT" }) }}
|
||||
</a>
|
||||
@@ -58,7 +58,7 @@
|
||||
"
|
||||
>
|
||||
<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>
|
||||
{{ $t("toolbar.show", { std: "STDERR" }) }}
|
||||
</a>
|
||||
@@ -102,9 +102,10 @@ const downloadUrl = computed(() =>
|
||||
);
|
||||
</script>
|
||||
|
||||
<style scoped lang="postcss">
|
||||
<style scoped>
|
||||
@import "@/main.css" reference;
|
||||
li.line {
|
||||
@apply h-px bg-base-content/20;
|
||||
@apply bg-base-content/20 h-px;
|
||||
}
|
||||
|
||||
a {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<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="col-start-1 row-start-1 truncate px-2 brightness-100 [direction:rtl]">{{ value }}</div>
|
||||
</div>
|
||||
@@ -36,7 +36,7 @@ const { value } = defineProps<{
|
||||
const color = computed(() => colors[Math.abs(hashCode(value)) % colors.length]);
|
||||
</script>
|
||||
|
||||
<style lang="postcss" scoped>
|
||||
<style scoped>
|
||||
.random-color {
|
||||
background-color: v-bind(color);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<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>
|
||||
<tr>
|
||||
<th v-for="column in columns" :key="column">{{ column }}</th>
|
||||
@@ -11,18 +11,18 @@
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table class="table table-md animate-pulse" v-else>
|
||||
<table class="table-md table animate-pulse" v-else>
|
||||
<thead>
|
||||
<tr>
|
||||
<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>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="_ in 9">
|
||||
<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>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<template>
|
||||
<LogItem :logEntry>
|
||||
<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))"
|
||||
></div>
|
||||
<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))"
|
||||
: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>`);
|
||||
</script>
|
||||
|
||||
<style scoped lang="postcss">
|
||||
<style scoped>
|
||||
@import "@/main.css" reference;
|
||||
.log-wrapper :deep(a) {
|
||||
@apply text-primary underline-offset-4 hover:underline;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<div class="my-4 flex-1 text-center">
|
||||
<div class="relative">
|
||||
<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 }) }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
<template>
|
||||
<div class="relative hover:text-secondary" @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="hover:text-secondary relative" @mouseenter="mouseOver = true" @mouseleave="mouseOver = false">
|
||||
<div class="border-primary hidden overflow-hidden rounded-xs border px-px pt-1 pb-px md:flex">
|
||||
<StatSparkline :data="data" @selected-point="onSelectedPoint" />
|
||||
</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="select-none font-bold">
|
||||
{{ mouseOver ? selectedPoint?.value ?? selectedPoint?.y ?? statValue : statValue }}
|
||||
<div class="font-bold select-none">
|
||||
{{ mouseOver ? (selectedPoint?.value ?? selectedPoint?.y ?? statValue) : statValue }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<svg :width="width" :height="height" @mousemove="onMove" class="group">
|
||||
<path :d="path" class="fill-primary" />
|
||||
<line :x1="lineX" y1="0" :x2="lineX" :y2="height" class="invisible stroke-secondary stroke-2 group-hover:visible" />
|
||||
<line :x1="lineX" y1="0" :x2="lineX" :y2="height" class="stroke-secondary invisible stroke-2 group-hover:visible" />
|
||||
</svg>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -7,12 +7,12 @@ exports[`<ContainerEventSource /> > render html correctly > should render dates
|
||||
<!--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="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="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 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 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="flex gap-2 duration-250 absolute -right-1 opacity-0 transition-opacity delay-150 group-hover/entry:opacity-100">
|
||||
<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 absolute -right-1 opacity-0 transition-opacity delay-150 duration-250 group-hover/entry:opacity-100">
|
||||
<!--v-if-->
|
||||
</div>
|
||||
</div>
|
||||
@@ -27,12 +27,12 @@ exports[`<ContainerEventSource /> > render html correctly > should render dates
|
||||
<!--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="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="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 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 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="flex gap-2 duration-250 absolute -right-1 opacity-0 transition-opacity delay-150 group-hover/entry:opacity-100">
|
||||
<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 absolute -right-1 opacity-0 transition-opacity delay-150 duration-250 group-hover/entry:opacity-100">
|
||||
<!--v-if-->
|
||||
</div>
|
||||
</div>
|
||||
@@ -47,12 +47,12 @@ exports[`<ContainerEventSource /> > render html correctly > should render messag
|
||||
<!--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="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="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 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 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="flex gap-2 duration-250 absolute -right-1 opacity-0 transition-opacity delay-150 group-hover/entry:opacity-100">
|
||||
<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 absolute -right-1 opacity-0 transition-opacity delay-150 duration-250 group-hover/entry:opacity-100">
|
||||
<!--v-if-->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<ScrollableView :scrollable="scrollable" v-if="containers.length && ready">
|
||||
<template #header>
|
||||
<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 />
|
||||
<div class="inline-flex font-mono text-sm">
|
||||
<div class="font-semibold">{{ containers.length }} containers</div>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<transition name="fade">
|
||||
<div
|
||||
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"
|
||||
>
|
||||
<slot name="content"></slot>
|
||||
@@ -45,7 +45,7 @@ useEventListener(() => el.value?.nextElementSibling, "mouseenter", onMouseEnter)
|
||||
useEventListener(() => el.value?.nextElementSibling, "mouseleave", onMouseLeave);
|
||||
</script>
|
||||
|
||||
<style scoped lang="postcss">
|
||||
<style scoped>
|
||||
.fade-enter-active,
|
||||
.fade-leave-active {
|
||||
@apply transition-opacity;
|
||||
|
||||
@@ -2,21 +2,21 @@
|
||||
<ul class="space-y-4 p-2">
|
||||
<li v-for="release in releases" v-if="releases?.length">
|
||||
<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">
|
||||
{{ release.name }}
|
||||
</a>
|
||||
<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") }}
|
||||
</Tag>
|
||||
</div>
|
||||
<div class="text-sm text-base-content/80">
|
||||
<div class="text-base-content/80 text-sm">
|
||||
{{ summary(release) }}
|
||||
</div>
|
||||
</li>
|
||||
<li v-else>
|
||||
<div class="text-sm text-base-content/80">
|
||||
<div class="text-base-content/80 text-sm">
|
||||
{{ $t("releases.no_releases") }}
|
||||
</div>
|
||||
</li>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<div class="inline-flex flex-col items-end gap-2" ref="root" v-show="!autoHide || show">
|
||||
<div class="relative inline-block">
|
||||
<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>
|
||||
<div class="absolute inset-0 flex items-center justify-center font-light">
|
||||
<span class="text-4xl">
|
||||
@@ -12,7 +12,7 @@
|
||||
<span> % </span>
|
||||
</div>
|
||||
</div>
|
||||
<DistanceTime :date="date" class="whitespace-nowrap text-sm" />
|
||||
<DistanceTime :date="date" class="text-sm whitespace-nowrap" />
|
||||
</div>
|
||||
</transition>
|
||||
</template>
|
||||
@@ -41,7 +41,7 @@ watch(
|
||||
},
|
||||
);
|
||||
</script>
|
||||
<style scoped lang="postcss">
|
||||
<style scoped>
|
||||
svg {
|
||||
filter: drop-shadow(0px 1px 1px rgba(0, 0, 0, 0.2));
|
||||
margin-top: 5px;
|
||||
|
||||
@@ -2,19 +2,19 @@
|
||||
<section :class="{ 'h-screen min-h-0': scrollable }" class="flex flex-col">
|
||||
<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>
|
||||
</header>
|
||||
<main :data-scrolling="scrollable ? true : undefined" class="snap-y overflow-auto">
|
||||
<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
|
||||
:indeterminate="loadingMore"
|
||||
:auto-hide="!loadingMore"
|
||||
:progress="scrollContext.progress"
|
||||
:date="scrollContext.currentDate"
|
||||
class="!fixed z-10 min-w-40"
|
||||
class="fixed! z-10 min-w-40"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -28,7 +28,7 @@
|
||||
<div class="mr-16 text-right">
|
||||
<transition name="fade">
|
||||
<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' : ''"
|
||||
@click="scrollToBottom()"
|
||||
v-show="scrollContext.paused"
|
||||
@@ -77,7 +77,7 @@ function scrollToBottom(behavior: "auto" | "smooth" = "auto") {
|
||||
hasMore.value = false;
|
||||
}
|
||||
</script>
|
||||
<style scoped lang="postcss">
|
||||
<style scoped>
|
||||
.fade-enter-active,
|
||||
.fade-leave-active {
|
||||
@apply transition-opacity;
|
||||
|
||||
@@ -7,10 +7,7 @@
|
||||
ref="container"
|
||||
:style="style"
|
||||
>
|
||||
<div
|
||||
class="input input-primary flex h-auto items-center !shadow-lg"
|
||||
:class="!isValidQuery ? 'input-warning' : ''"
|
||||
>
|
||||
<div class="input input-primary flex items-center shadow-lg" :class="!isValidQuery ? 'input-warning' : ''">
|
||||
<mdi:magnify />
|
||||
<input
|
||||
class="input input-ghost w-72 flex-1"
|
||||
@@ -57,7 +54,7 @@ onMounted(() => {
|
||||
onUnmounted(() => resetSearch());
|
||||
</script>
|
||||
|
||||
<style lang="postcss" scoped>
|
||||
<style scoped>
|
||||
.slide-enter-active,
|
||||
.slide-leave-active {
|
||||
transition: all 200ms cubic-bezier(0.175, 0.885, 0.32, 1.275);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<ScrollableView :scrollable="scrollable" v-if="service.name">
|
||||
<template #header>
|
||||
<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 />
|
||||
<div class="inline-flex font-mono text-sm">
|
||||
<div class="font-semibold">{{ service.name }}</div>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
</Carousel>
|
||||
</div>
|
||||
<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>
|
||||
</div>
|
||||
</template>
|
||||
@@ -35,4 +35,4 @@ watch(
|
||||
{ immediate: true },
|
||||
);
|
||||
</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">
|
||||
<h1>
|
||||
<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>
|
||||
|
||||
<small class="mb-4 block text-xs font-light" v-if="hostname">
|
||||
@@ -11,7 +11,7 @@
|
||||
</h1>
|
||||
|
||||
<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')"
|
||||
:title="$t('tooltip.search')"
|
||||
data-testid="search"
|
||||
@@ -30,14 +30,4 @@ import LogoWithText from "@/logo-text.svg";
|
||||
const { hostname } = config;
|
||||
</script>
|
||||
|
||||
<style scoped lang="postcss">
|
||||
.logo {
|
||||
:deep(.content-fill) {
|
||||
@apply fill-base-content;
|
||||
}
|
||||
|
||||
:deep(.secondary-fill) {
|
||||
@apply fill-secondary;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<style scoped></style>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<ScrollableView :scrollable="scrollable" v-if="stack.name">
|
||||
<template #header>
|
||||
<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 />
|
||||
<div class="inline-flex font-mono text-sm">
|
||||
<div class="font-semibold">{{ stack.name }}</div>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<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">
|
||||
<details open>
|
||||
<summary class="font-light text-base-content/80">
|
||||
<summary class="text-base-content/80 font-light">
|
||||
<ph:stack />
|
||||
{{ name }}
|
||||
|
||||
@@ -17,10 +17,7 @@
|
||||
</summary>
|
||||
<ul>
|
||||
<li v-for="service in services" :key="service.name">
|
||||
<router-link
|
||||
:to="{ name: '/service/[name]', params: { name: service.name } }"
|
||||
active-class="active-primary"
|
||||
>
|
||||
<router-link :to="{ name: '/service/[name]', params: { name: service.name } }" active-class="menu-active">
|
||||
<ph:stack-simple />
|
||||
<div class="truncate">
|
||||
{{ service.name }}
|
||||
@@ -33,16 +30,13 @@
|
||||
|
||||
<li v-if="serivcesWithoutStacks.length > 0">
|
||||
<details open>
|
||||
<summary class="font-light text-base-content/80">
|
||||
<summary class="text-base-content/80 font-light">
|
||||
<ph:circles-four />
|
||||
{{ $t("label.services") }}
|
||||
</summary>
|
||||
<ul>
|
||||
<li v-for="service in serivcesWithoutStacks" :key="service.name">
|
||||
<router-link
|
||||
:to="{ name: '/service/[name]', params: { name: service.name } }"
|
||||
active-class="active-primary"
|
||||
>
|
||||
<router-link :to="{ name: '/service/[name]', params: { name: service.name } }" active-class="menu-active">
|
||||
<ph:stack-simple />
|
||||
<div class="truncate">
|
||||
{{ service.name }}
|
||||
@@ -55,13 +49,13 @@
|
||||
|
||||
<li v-if="customGroups.length > 0">
|
||||
<details open>
|
||||
<summary class="font-light text-base-content/80">
|
||||
<summary class="text-base-content/80 font-light">
|
||||
<ph:bounding-box-fill />
|
||||
{{ $t("label.custom-groups") }}
|
||||
</summary>
|
||||
<ul>
|
||||
<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 />
|
||||
<div class="truncate">
|
||||
{{ group.name }}
|
||||
@@ -81,7 +75,7 @@ const { stacks, services, customGroups } = storeToRefs(store);
|
||||
|
||||
const serivcesWithoutStacks = computed(() => services.value.filter((service) => !service.stack));
|
||||
</script>
|
||||
<style scoped lang="postcss">
|
||||
<style scoped>
|
||||
.menu {
|
||||
@apply text-[0.95rem];
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
@click="scrollToItem(index)"
|
||||
:class="[
|
||||
'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"
|
||||
:title="c.props?.title"
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
</label>
|
||||
<div
|
||||
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>
|
||||
</div>
|
||||
|
||||
@@ -3,7 +3,9 @@
|
||||
<summary class="btn btn-primary flex-nowrap" v-bind="$attrs">
|
||||
<slot name="trigger"> {{ label }} <carbon:caret-down /></slot>
|
||||
</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>
|
||||
<li v-for="item in options">
|
||||
<a @click="update(item.value as T)">
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<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>
|
||||
<script setup lang="ts">
|
||||
const { color = "primary" } = defineProps<{ color: "primary" | "error" | "secondary" }>();
|
||||
@@ -16,7 +16,7 @@ const colorClass = computed(() => {
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="postcss">
|
||||
<style scoped>
|
||||
.animate-background {
|
||||
animation: gradient-animation 3s ease-out infinite;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<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" />
|
||||
</label>
|
||||
</template>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<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">
|
||||
<router-link :to="{ name: '/' }">
|
||||
<Logo class="logo h-8" />
|
||||
<Logo class="logo [&_.secondary-fill]:fill-secondary h-8" />
|
||||
</router-link>
|
||||
|
||||
<div class="ml-auto flex items-center gap-2">
|
||||
@@ -18,7 +18,7 @@
|
||||
</div>
|
||||
|
||||
<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" />
|
||||
</div>
|
||||
</transition>
|
||||
@@ -34,7 +34,8 @@ watch(route, () => {
|
||||
show.value = false;
|
||||
});
|
||||
</script>
|
||||
<style scoped lang="postcss">
|
||||
<style scoped>
|
||||
@import "@/main.css" reference;
|
||||
.fade-enter-active,
|
||||
.fade-leave-active {
|
||||
@apply transition-opacity;
|
||||
@@ -54,10 +55,4 @@ watch(route, () => {
|
||||
.fade-leave-to > div {
|
||||
@apply -translate-y-10;
|
||||
}
|
||||
|
||||
.logo {
|
||||
:deep(.secondary-fill) {
|
||||
@apply fill-secondary;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<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">
|
||||
<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:close class="swap-on" />
|
||||
</button>
|
||||
@@ -32,9 +32,11 @@ defineExpose({
|
||||
|
||||
useEventListener(panel, "close", () => (open.value = false));
|
||||
</script>
|
||||
<style scoped lang="postcss">
|
||||
<style scoped>
|
||||
@import "@/main.css" reference;
|
||||
|
||||
.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"] {
|
||||
@apply max-w-3xl;
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<script lang="ts" setup>
|
||||
const { slideRight } = defineProps<{ slideRight: boolean }>();
|
||||
</script>
|
||||
<style scoped lang="postcss">
|
||||
<style scoped>
|
||||
.slide-left-enter-active,
|
||||
.slide-left-leave-active,
|
||||
.slide-right-enter-active,
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
<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>
|
||||
</div>
|
||||
</template>
|
||||
@@ -7,9 +10,3 @@
|
||||
<script lang="ts" setup>
|
||||
const { size = undefined } = defineProps<{ size?: "small" | undefined }>();
|
||||
</script>
|
||||
|
||||
<style scoped lang="postcss">
|
||||
[size="small"] {
|
||||
@apply text-xs;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -40,4 +40,4 @@ const cancel = () => {
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="postcss"></style>
|
||||
<style scoped></style>
|
||||
|
||||
@@ -25,8 +25,8 @@
|
||||
</pane>
|
||||
</splitpanes>
|
||||
<label
|
||||
class="btn btn-circle swap btn-neutral swap-rotate fixed -left-12 bottom-4 w-16 transition-all hover:-left-4"
|
||||
:class="{ '!-left-6': collapseNav }"
|
||||
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 }"
|
||||
v-if="!isMobile && !forceMenuHidden"
|
||||
>
|
||||
<input type="checkbox" v-model="collapseNav" />
|
||||
@@ -34,7 +34,7 @@
|
||||
<mdi:chevron-left class="swap-off" />
|
||||
</label>
|
||||
</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">
|
||||
<FuzzySearchModal @close="open = false" v-if="open" />
|
||||
</div>
|
||||
@@ -117,9 +117,11 @@ function onResized(e: any) {
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="postcss">
|
||||
<style scoped>
|
||||
@import "@/main.css" reference;
|
||||
|
||||
: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) {
|
||||
|
||||
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;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
@theme {
|
||||
--color-green: oklch(69% 0.119722 188.479048);
|
||||
--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 {
|
||||
: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) {
|
||||
body {
|
||||
-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>
|
||||
<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="max-w-md">
|
||||
<p class="py-6 text-2xl font-bold">{{ $t("error.page-not-found") }}</p>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<Search />
|
||||
<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="max-w-md">
|
||||
<p class="py-6 text-2xl font-bold">{{ $t("error.container-not-found") }}</p>
|
||||
|
||||
@@ -29,7 +29,7 @@ watchEffect(() => {
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<style lang="postcss" scoped>
|
||||
<style scoped>
|
||||
:deep(tr td) {
|
||||
padding-top: 1em;
|
||||
padding-bottom: 1em;
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
<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">
|
||||
<form action="" method="post" @submit.prevent="onLogin" ref="form" class="flex flex-col gap-8">
|
||||
<label class="form-control w-full">
|
||||
<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 }"
|
||||
>
|
||||
<span class="ml-5">{{ $t("label.username") }}</span>
|
||||
<mdi:account class="has-[+:focus]:text-primary" :class="{ 'text-error': error }" />
|
||||
<input
|
||||
type="text"
|
||||
class="grow"
|
||||
:class="{ 'text-error': error }"
|
||||
:placeholder="$t('label.username')"
|
||||
name="username"
|
||||
@@ -27,11 +27,13 @@
|
||||
</label>
|
||||
</label>
|
||||
<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" />
|
||||
<input
|
||||
type="password"
|
||||
class="grow"
|
||||
:placeholder="$t('label.password')"
|
||||
name="password"
|
||||
autocomplete="current-password"
|
||||
|
||||
@@ -14,13 +14,13 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="flex flex-col @container">
|
||||
<section class="@container flex flex-col">
|
||||
<div class="has-underline">
|
||||
<h2>{{ $t("settings.display") }}</h2>
|
||||
</div>
|
||||
|
||||
<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="smallerScrollbars"> {{ $t("settings.small-scrollbars") }} </Toggle>
|
||||
@@ -51,7 +51,7 @@
|
||||
{{ $t("settings.datetime-format") }}
|
||||
</template>
|
||||
<template #input>
|
||||
<div class="flex gap-2">
|
||||
<div class="flex gap-4">
|
||||
<DropdownMenu
|
||||
v-model="dateLocale"
|
||||
:options="[
|
||||
@@ -110,28 +110,22 @@
|
||||
:messages="fakeMessages"
|
||||
:last-selected-item="undefined"
|
||||
: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 class="flex flex-col gap-2">
|
||||
<section class="flex flex-col gap-4">
|
||||
<div class="has-underline">
|
||||
<h2>{{ $t("settings.options") }}</h2>
|
||||
</div>
|
||||
<div>
|
||||
<toggle v-model="search">
|
||||
{{ $t("settings.search") }} <key-shortcut char="f" class="align-top"></key-shortcut>
|
||||
</toggle>
|
||||
</div>
|
||||
<Toggle v-model="search">
|
||||
{{ $t("settings.search") }} <key-shortcut char="f" class="align-top"></key-shortcut>
|
||||
</Toggle>
|
||||
|
||||
<div>
|
||||
<toggle v-model="showAllContainers">{{ $t("settings.show-stopped-containers") }}</toggle>
|
||||
</div>
|
||||
<Toggle v-model="showAllContainers">{{ $t("settings.show-stopped-containers") }}</Toggle>
|
||||
|
||||
<div>
|
||||
<toggle v-model="automaticRedirect">{{ $t("settings.automatic-redirect") }}</toggle>
|
||||
</div>
|
||||
<Toggle v-model="automaticRedirect">{{ $t("settings.automatic-redirect") }}</Toggle>
|
||||
</section>
|
||||
</PageWithLinks>
|
||||
</template>
|
||||
@@ -211,9 +205,15 @@ const fakeMessages = computedWithControl(
|
||||
],
|
||||
);
|
||||
</script>
|
||||
<style lang="postcss" scoped>
|
||||
<style scoped>
|
||||
@import "@/main.css" reference;
|
||||
|
||||
.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)) {
|
||||
|
||||
@@ -1,18 +1,13 @@
|
||||
<script setup>
|
||||
import { data } from "../../activity.data.ts";
|
||||
import Counter from "./Counter.vue";
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<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-value">
|
||||
<Counter :start="0" :end="data.stars" :duration="1000" :formatter="(value) => (value / 1e3).toFixed(1) + 'K'" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="stat !border-l-0">
|
||||
<div class="stat">
|
||||
<div class="stat-title">Docker Pulls</div>
|
||||
<div class="stat-value">
|
||||
<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>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { data } from "../../activity.data";
|
||||
import Counter from "./Counter.vue";
|
||||
</script>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
@import "tailwindcss";
|
||||
@plugin "daisyui" {
|
||||
include: stat;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 tailwindcss from "@tailwindcss/vite";
|
||||
import { defineConfig } from "vite";
|
||||
|
||||
import Components from "unplugin-vue-components/vite";
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
tailwindcss(),
|
||||
Components({
|
||||
dirs: [path.resolve(__dirname, ".vitepress/theme/components")],
|
||||
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/ph": "^1.2.2",
|
||||
"@intlify/unplugin-vue-i18n": "^6.0.3",
|
||||
"@tailwindcss/container-queries": "^0.1.1",
|
||||
"@tailwindcss/typography": "^0.5.15",
|
||||
"@tailwindcss/vite": "4.0.0-beta.8",
|
||||
"@vueuse/components": "^12.3.0",
|
||||
"@vueuse/core": "^12.3.0",
|
||||
"@vueuse/integrations": "^12.3.0",
|
||||
"@vueuse/router": "^12.3.0",
|
||||
"ansi-to-html": "^0.7.2",
|
||||
"autoprefixer": "^10.4.20",
|
||||
"d3-array": "^3.2.4",
|
||||
"d3-ease": "^3.0.1",
|
||||
"d3-scale": "^4.0.2",
|
||||
"d3-selection": "^3.0.0",
|
||||
"d3-shape": "^3.2.0",
|
||||
"d3-transition": "^3.0.1",
|
||||
"daisyui": "^4.12.23",
|
||||
"daisyui": "5.0.0-beta.1",
|
||||
"date-fns": "^4.1.0",
|
||||
"entities": "^6.0.0",
|
||||
"fuse.js": "^7.0.0",
|
||||
"lodash.debounce": "^4.0.8",
|
||||
"pinia": "^2.3.0",
|
||||
"postcss": "^8.4.49",
|
||||
"sortablejs": "^1.15.6",
|
||||
"splitpanes": "^3.1.5",
|
||||
"strip-ansi": "^7.1.0",
|
||||
"tailwindcss": "^3.4.17",
|
||||
"tailwindcss": "4.0.0-beta.8",
|
||||
"unplugin-auto-import": "^0.19.0",
|
||||
"unplugin-icons": "^0.22.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>
|
||||
<html class="bg-base text-base-content">
|
||||
<html class="bg-base-200 text-base-content">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<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 { VueRouterAutoImports } from "unplugin-vue-router";
|
||||
import svgLoader from "vite-svg-loader";
|
||||
import tailwindcss from "@tailwindcss/vite";
|
||||
|
||||
export default defineConfig(() => ({
|
||||
resolve: {
|
||||
@@ -73,6 +74,7 @@ export default defineConfig(() => ({
|
||||
}),
|
||||
compression({ algorithm: "brotliCompress", exclude: [/\.(html)$/] }),
|
||||
svgLoader({}),
|
||||
tailwindcss(),
|
||||
],
|
||||
test: {
|
||||
include: ["assets/**/*.spec.ts"],
|
||||
|
||||