1
0
mirror of https://github.com/amir20/dozzle.git synced 2025-12-21 13:23:07 +01:00

chore: upgrades to tailwind v4 and daisyUI v5 🎨 (#3505)

This commit is contained in:
Amir Raminfar
2025-01-05 13:38:36 -08:00
committed by GitHub
parent 40015f7385
commit efa95078ac
74 changed files with 701 additions and 843 deletions

View File

@@ -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;

View File

@@ -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;

View File

@@ -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 {

View File

@@ -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;
} }

View File

@@ -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]" />

View File

@@ -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" />

View File

@@ -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;
} }

View File

@@ -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>

View File

@@ -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>

View File

@@ -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];
} }

View File

@@ -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>

View File

@@ -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>

View File

@@ -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;
} }

View File

@@ -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;
} }

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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;
} }
} }

View File

@@ -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;

View File

@@ -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>

View File

@@ -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 />

View 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;
} }

View File

@@ -39,4 +39,4 @@ watchEffect(() => {
}); });
}); });
</script> </script>
<style scoped lang="postcss"></style> <style scoped></style>

View File

@@ -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 {

View File

@@ -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);
} }

View File

@@ -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>

View File

@@ -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;
} }

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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;

View File

@@ -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>

View File

@@ -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;

View File

@@ -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;

View File

@@ -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);

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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];
} }

View File

@@ -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"

View File

@@ -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>

View File

@@ -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)">

View File

@@ -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;
} }

View File

@@ -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>

View File

@@ -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>

View File

@@ -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;

View File

@@ -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,

View File

@@ -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>

View File

@@ -40,4 +40,4 @@ const cancel = () => {
}; };
</script> </script>
<style scoped lang="postcss"></style> <style scoped></style>

View File

@@ -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) {

View File

@@ -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;
}
} }

View File

@@ -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>

View File

@@ -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>

View File

@@ -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;

View File

@@ -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"

View File

@@ -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)) {

View File

@@ -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>

View File

@@ -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:

View File

@@ -1,6 +0,0 @@
module.exports = {
plugins: {
tailwindcss: { config: "./docs/tailwind.docs.ts" },
autoprefixer: {},
},
};

View File

@@ -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;

View File

@@ -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"],

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View File

@@ -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

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +0,0 @@
module.exports = {
plugins: {
"tailwindcss/nesting": {},
tailwindcss: {},
autoprefixer: {},
},
};

View File

@@ -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" />

View File

@@ -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;

View File

@@ -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"],