mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-29 02:32:18 +00:00
[backport rh-test] make topbar badges responsive and fix server health badges showing on unrelated dialogs (#6297)
Backport of #6291 to `rh-test` Automatically created by backport workflow. ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-6297-backport-rh-test-make-topbar-badges-responsive-and-fix-server-health-badges-showing-on--2986d73d365081d1ba58fb40eb8d2776) by [Unito](https://www.unito.io) --------- Co-authored-by: Christian Byrne <cbyrne@comfy.org> Co-authored-by: GitHub Action <action@github.com>
This commit is contained in:
38
src/components/topbar/CloudBadge.vue
Normal file
38
src/components/topbar/CloudBadge.vue
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
<template>
|
||||||
|
<TopbarBadge
|
||||||
|
:badge="cloudBadge"
|
||||||
|
:display-mode="displayMode"
|
||||||
|
:reverse-order="reverseOrder"
|
||||||
|
:no-padding="noPadding"
|
||||||
|
:background-color="backgroundColor"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { computed } from 'vue'
|
||||||
|
|
||||||
|
import { t } from '@/i18n'
|
||||||
|
import type { TopbarBadge as TopbarBadgeType } from '@/types/comfy'
|
||||||
|
|
||||||
|
import TopbarBadge from './TopbarBadge.vue'
|
||||||
|
|
||||||
|
withDefaults(
|
||||||
|
defineProps<{
|
||||||
|
displayMode?: 'full' | 'compact' | 'icon-only'
|
||||||
|
reverseOrder?: boolean
|
||||||
|
noPadding?: boolean
|
||||||
|
backgroundColor?: string
|
||||||
|
}>(),
|
||||||
|
{
|
||||||
|
displayMode: 'full',
|
||||||
|
reverseOrder: false,
|
||||||
|
noPadding: false,
|
||||||
|
backgroundColor: 'var(--comfy-menu-bg)'
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
const cloudBadge = computed<TopbarBadgeType>(() => ({
|
||||||
|
label: t('g.beta'),
|
||||||
|
text: 'Comfy Cloud'
|
||||||
|
}))
|
||||||
|
</script>
|
||||||
231
src/components/topbar/TopbarBadge.test.ts
Normal file
231
src/components/topbar/TopbarBadge.test.ts
Normal file
@@ -0,0 +1,231 @@
|
|||||||
|
import { mount } from '@vue/test-utils'
|
||||||
|
import PrimeVue from 'primevue/config'
|
||||||
|
import Popover from 'primevue/popover'
|
||||||
|
import Tooltip from 'primevue/tooltip'
|
||||||
|
import { describe, expect, it } from 'vitest'
|
||||||
|
import { createI18n } from 'vue-i18n'
|
||||||
|
|
||||||
|
import type { TopbarBadge as TopbarBadgeType } from '@/types/comfy'
|
||||||
|
|
||||||
|
import TopbarBadge from './TopbarBadge.vue'
|
||||||
|
|
||||||
|
const i18n = createI18n({
|
||||||
|
legacy: false,
|
||||||
|
locale: 'en',
|
||||||
|
messages: {
|
||||||
|
en: {}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('TopbarBadge', () => {
|
||||||
|
const exampleBadge: TopbarBadgeType = {
|
||||||
|
text: 'Test Badge',
|
||||||
|
label: 'BETA',
|
||||||
|
variant: 'info'
|
||||||
|
}
|
||||||
|
|
||||||
|
const mountTopbarBadge = (
|
||||||
|
badge: Partial<TopbarBadgeType> = {},
|
||||||
|
displayMode: 'full' | 'compact' | 'icon-only' = 'full'
|
||||||
|
) => {
|
||||||
|
return mount(TopbarBadge, {
|
||||||
|
global: {
|
||||||
|
plugins: [PrimeVue, i18n],
|
||||||
|
directives: { tooltip: Tooltip },
|
||||||
|
components: { Popover }
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
badge: { ...exampleBadge, ...badge },
|
||||||
|
displayMode
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('full display mode', () => {
|
||||||
|
it('renders all badge elements (icon, label, text)', () => {
|
||||||
|
const wrapper = mountTopbarBadge(
|
||||||
|
{
|
||||||
|
text: 'Comfy Cloud',
|
||||||
|
label: 'BETA',
|
||||||
|
icon: 'pi pi-cloud'
|
||||||
|
},
|
||||||
|
'full'
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(wrapper.find('.pi-cloud').exists()).toBe(true)
|
||||||
|
expect(wrapper.text()).toContain('BETA')
|
||||||
|
expect(wrapper.text()).toContain('Comfy Cloud')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('renders without icon when not provided', () => {
|
||||||
|
const wrapper = mountTopbarBadge(
|
||||||
|
{
|
||||||
|
text: 'Test',
|
||||||
|
label: 'NEW'
|
||||||
|
},
|
||||||
|
'full'
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(wrapper.find('i').exists()).toBe(false)
|
||||||
|
expect(wrapper.text()).toContain('NEW')
|
||||||
|
expect(wrapper.text()).toContain('Test')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('compact display mode', () => {
|
||||||
|
it('renders icon and label but not text', () => {
|
||||||
|
const wrapper = mountTopbarBadge(
|
||||||
|
{
|
||||||
|
text: 'Hidden Text',
|
||||||
|
label: 'BETA',
|
||||||
|
icon: 'pi pi-cloud'
|
||||||
|
},
|
||||||
|
'compact'
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(wrapper.find('.pi-cloud').exists()).toBe(true)
|
||||||
|
expect(wrapper.text()).toContain('BETA')
|
||||||
|
expect(wrapper.text()).not.toContain('Hidden Text')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('opens popover on click', async () => {
|
||||||
|
const wrapper = mountTopbarBadge(
|
||||||
|
{
|
||||||
|
text: 'Full Text',
|
||||||
|
label: 'ALERT'
|
||||||
|
},
|
||||||
|
'compact'
|
||||||
|
)
|
||||||
|
|
||||||
|
const clickableArea = wrapper.find('[class*="flex h-full"]')
|
||||||
|
await clickableArea.trigger('click')
|
||||||
|
|
||||||
|
const popover = wrapper.findComponent(Popover)
|
||||||
|
expect(popover.exists()).toBe(true)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('icon-only display mode', () => {
|
||||||
|
it('renders only icon', () => {
|
||||||
|
const wrapper = mountTopbarBadge(
|
||||||
|
{
|
||||||
|
text: 'Hidden Text',
|
||||||
|
label: 'BETA',
|
||||||
|
icon: 'pi pi-cloud'
|
||||||
|
},
|
||||||
|
'icon-only'
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(wrapper.find('.pi-cloud').exists()).toBe(true)
|
||||||
|
expect(wrapper.text()).not.toContain('BETA')
|
||||||
|
expect(wrapper.text()).not.toContain('Hidden Text')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('renders label when no icon provided', () => {
|
||||||
|
const wrapper = mountTopbarBadge(
|
||||||
|
{
|
||||||
|
text: 'Hidden Text',
|
||||||
|
label: 'NEW'
|
||||||
|
},
|
||||||
|
'icon-only'
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(wrapper.text()).toContain('NEW')
|
||||||
|
expect(wrapper.text()).not.toContain('Hidden Text')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('badge variants', () => {
|
||||||
|
it('applies error variant styles', () => {
|
||||||
|
const wrapper = mountTopbarBadge(
|
||||||
|
{
|
||||||
|
text: 'Error Message',
|
||||||
|
label: 'ERROR',
|
||||||
|
variant: 'error'
|
||||||
|
},
|
||||||
|
'full'
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(wrapper.find('.bg-danger-100').exists()).toBe(true)
|
||||||
|
expect(wrapper.find('.text-danger-100').exists()).toBe(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('applies warning variant styles', () => {
|
||||||
|
const wrapper = mountTopbarBadge(
|
||||||
|
{
|
||||||
|
text: 'Warning Message',
|
||||||
|
label: 'WARN',
|
||||||
|
variant: 'warning'
|
||||||
|
},
|
||||||
|
'full'
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(wrapper.find('.bg-warning-100').exists()).toBe(true)
|
||||||
|
expect(wrapper.find('.text-warning-100').exists()).toBe(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('uses default error icon for error variant', () => {
|
||||||
|
const wrapper = mountTopbarBadge(
|
||||||
|
{
|
||||||
|
text: 'Error',
|
||||||
|
variant: 'error'
|
||||||
|
},
|
||||||
|
'full'
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(wrapper.find('.pi-exclamation-circle').exists()).toBe(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('uses default warning icon for warning variant', () => {
|
||||||
|
const wrapper = mountTopbarBadge(
|
||||||
|
{
|
||||||
|
text: 'Warning',
|
||||||
|
variant: 'warning'
|
||||||
|
},
|
||||||
|
'full'
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(wrapper.find('.pi-exclamation-triangle').exists()).toBe(true)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('popover', () => {
|
||||||
|
it('includes popover component in compact and icon-only modes', () => {
|
||||||
|
const compactWrapper = mountTopbarBadge({}, 'compact')
|
||||||
|
const iconOnlyWrapper = mountTopbarBadge({}, 'icon-only')
|
||||||
|
const fullWrapper = mountTopbarBadge({}, 'full')
|
||||||
|
|
||||||
|
expect(compactWrapper.findComponent(Popover).exists()).toBe(true)
|
||||||
|
expect(iconOnlyWrapper.findComponent(Popover).exists()).toBe(true)
|
||||||
|
expect(fullWrapper.findComponent(Popover).exists()).toBe(false)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('edge cases', () => {
|
||||||
|
it('handles badge with only text', () => {
|
||||||
|
const wrapper = mountTopbarBadge(
|
||||||
|
{
|
||||||
|
text: 'Simple Badge'
|
||||||
|
},
|
||||||
|
'full'
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(wrapper.text()).toContain('Simple Badge')
|
||||||
|
expect(wrapper.find('i').exists()).toBe(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('handles custom icon override', () => {
|
||||||
|
const wrapper = mountTopbarBadge(
|
||||||
|
{
|
||||||
|
text: 'Custom',
|
||||||
|
variant: 'error',
|
||||||
|
icon: 'pi pi-custom-icon'
|
||||||
|
},
|
||||||
|
'full'
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(wrapper.find('.pi-custom-icon').exists()).toBe(true)
|
||||||
|
expect(wrapper.find('.pi-exclamation-circle').exists()).toBe(false)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -1,9 +1,110 @@
|
|||||||
<template>
|
<template>
|
||||||
|
<!-- Icon-only mode with Popover -->
|
||||||
<div
|
<div
|
||||||
|
v-if="displayMode === 'icon-only'"
|
||||||
|
class="relative inline-flex h-full shrink-0 items-center justify-center px-2"
|
||||||
|
:class="clickableClasses"
|
||||||
|
:style="menuBackgroundStyle"
|
||||||
|
@click="togglePopover"
|
||||||
|
>
|
||||||
|
<i
|
||||||
|
v-if="iconClass"
|
||||||
|
:class="['shrink-0 text-base', iconClass, iconColorClass]"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
v-else-if="badge.label"
|
||||||
|
class="shrink-0 rounded-full px-1.5 py-0.5 text-xxxs font-semibold"
|
||||||
|
:class="labelClasses"
|
||||||
|
>
|
||||||
|
{{ badge.label }}
|
||||||
|
</div>
|
||||||
|
<div v-else class="size-2 shrink-0 rounded-full" :class="dotClasses" />
|
||||||
|
<Popover
|
||||||
|
ref="popover"
|
||||||
|
append-to="body"
|
||||||
|
:auto-z-index="true"
|
||||||
|
:base-z-index="1000"
|
||||||
|
:dismissable="true"
|
||||||
|
:close-on-escape="true"
|
||||||
|
unstyled
|
||||||
|
:pt="popoverPt"
|
||||||
|
>
|
||||||
|
<div class="flex max-w-xs min-w-40 flex-col gap-2 p-3">
|
||||||
|
<div
|
||||||
|
v-if="badge.label"
|
||||||
|
class="w-fit rounded-full px-1.5 py-0.5 text-xxxs font-semibold"
|
||||||
|
:class="labelClasses"
|
||||||
|
>
|
||||||
|
{{ badge.label }}
|
||||||
|
</div>
|
||||||
|
<div class="text-sm font-semibold">{{ badge.text }}</div>
|
||||||
|
<div v-if="badge.tooltip" class="text-xs">
|
||||||
|
{{ badge.tooltip }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Popover>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Compact mode: Icon + Label only with Popover -->
|
||||||
|
<div
|
||||||
|
v-else-if="displayMode === 'compact'"
|
||||||
|
class="relative inline-flex h-full"
|
||||||
|
:style="menuBackgroundStyle"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="flex h-full shrink-0 items-center gap-2 whitespace-nowrap"
|
||||||
|
:class="[
|
||||||
|
{ 'flex-row-reverse': reverseOrder },
|
||||||
|
noPadding ? '' : 'px-3',
|
||||||
|
clickableClasses
|
||||||
|
]"
|
||||||
|
@click="togglePopover"
|
||||||
|
>
|
||||||
|
<i
|
||||||
|
v-if="iconClass"
|
||||||
|
:class="['shrink-0 text-base', iconClass, iconColorClass]"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
v-if="badge.label"
|
||||||
|
class="shrink-0 rounded-full px-1.5 py-0.5 text-xxxs font-semibold"
|
||||||
|
:class="labelClasses"
|
||||||
|
>
|
||||||
|
{{ badge.label }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Popover
|
||||||
|
ref="popover"
|
||||||
|
append-to="body"
|
||||||
|
:auto-z-index="true"
|
||||||
|
:base-z-index="1000"
|
||||||
|
:dismissable="true"
|
||||||
|
:close-on-escape="true"
|
||||||
|
unstyled
|
||||||
|
:pt="popoverPt"
|
||||||
|
>
|
||||||
|
<div class="flex max-w-xs min-w-40 flex-col gap-2 p-3">
|
||||||
|
<div
|
||||||
|
v-if="badge.label"
|
||||||
|
class="w-fit rounded-full px-1.5 py-0.5 text-xxxs font-semibold"
|
||||||
|
:class="labelClasses"
|
||||||
|
>
|
||||||
|
{{ badge.label }}
|
||||||
|
</div>
|
||||||
|
<div class="text-sm font-semibold">{{ badge.text }}</div>
|
||||||
|
<div v-if="badge.tooltip" class="text-xs">
|
||||||
|
{{ badge.tooltip }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Popover>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Full mode: Icon + Label + Text -->
|
||||||
|
<div
|
||||||
|
v-else
|
||||||
v-tooltip="badge.tooltip"
|
v-tooltip="badge.tooltip"
|
||||||
class="flex h-full shrink-0 items-center gap-2 whitespace-nowrap"
|
class="flex h-full shrink-0 items-center gap-2 whitespace-nowrap"
|
||||||
:class="[{ 'flex-row-reverse': reverseOrder }, noPadding ? '' : 'px-3']"
|
:class="[{ 'flex-row-reverse': reverseOrder }, noPadding ? '' : 'px-3']"
|
||||||
:style="{ backgroundColor: 'var(--comfy-menu-bg)' }"
|
:style="menuBackgroundStyle"
|
||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
v-if="iconClass"
|
v-if="iconClass"
|
||||||
@@ -22,24 +123,40 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed } from 'vue'
|
import Popover from 'primevue/popover'
|
||||||
|
import { computed, ref } from 'vue'
|
||||||
|
|
||||||
import type { TopbarBadge } from '@/types/comfy'
|
import type { TopbarBadge } from '@/types/comfy'
|
||||||
|
import { cn } from '@/utils/tailwindUtil'
|
||||||
|
|
||||||
const props = withDefaults(
|
const props = withDefaults(
|
||||||
defineProps<{
|
defineProps<{
|
||||||
badge: TopbarBadge
|
badge: TopbarBadge
|
||||||
|
displayMode?: 'full' | 'compact' | 'icon-only'
|
||||||
reverseOrder?: boolean
|
reverseOrder?: boolean
|
||||||
noPadding?: boolean
|
noPadding?: boolean
|
||||||
|
backgroundColor?: string
|
||||||
}>(),
|
}>(),
|
||||||
{
|
{
|
||||||
|
displayMode: 'full',
|
||||||
reverseOrder: false,
|
reverseOrder: false,
|
||||||
noPadding: false
|
noPadding: false,
|
||||||
|
backgroundColor: 'var(--comfy-menu-bg)'
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const popover = ref<InstanceType<typeof Popover>>()
|
||||||
|
|
||||||
|
const togglePopover = (event: Event) => {
|
||||||
|
popover.value?.toggle(event)
|
||||||
|
}
|
||||||
|
|
||||||
const variant = computed(() => props.badge.variant ?? 'info')
|
const variant = computed(() => props.badge.variant ?? 'info')
|
||||||
|
|
||||||
|
const menuBackgroundStyle = computed(() => ({
|
||||||
|
backgroundColor: props.backgroundColor
|
||||||
|
}))
|
||||||
|
|
||||||
const labelClasses = computed(() => {
|
const labelClasses = computed(() => {
|
||||||
switch (variant.value) {
|
switch (variant.value) {
|
||||||
case 'error':
|
case 'error':
|
||||||
@@ -80,4 +197,33 @@ const iconClass = computed(() => {
|
|||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const clickableClasses = 'cursor-pointer transition-opacity hover:opacity-80'
|
||||||
|
|
||||||
|
const dotClasses = computed(() => {
|
||||||
|
switch (variant.value) {
|
||||||
|
case 'error':
|
||||||
|
return 'bg-danger-100'
|
||||||
|
case 'warning':
|
||||||
|
return 'bg-warning-100'
|
||||||
|
case 'info':
|
||||||
|
default:
|
||||||
|
return 'bg-slate-100'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const popoverPt = computed(() => ({
|
||||||
|
root: {
|
||||||
|
class: cn('absolute z-50')
|
||||||
|
},
|
||||||
|
content: {
|
||||||
|
class: cn(
|
||||||
|
'mt-1 rounded-lg',
|
||||||
|
'bg-white dark-theme:bg-zinc-800',
|
||||||
|
'text-neutral dark-theme:text-white',
|
||||||
|
'shadow-lg',
|
||||||
|
'border border-zinc-200 dark-theme:border-zinc-700'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}))
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
<template>
|
<template>
|
||||||
<div v-if="notMobile" class="flex h-full shrink-0 items-center">
|
<div class="flex h-full shrink-0 items-center">
|
||||||
<TopbarBadge
|
<TopbarBadge
|
||||||
v-for="badge in topbarBadgeStore.badges"
|
v-for="badge in topbarBadgeStore.badges"
|
||||||
:key="badge.text"
|
:key="badge.text"
|
||||||
:badge
|
:badge
|
||||||
|
:display-mode="displayMode"
|
||||||
:reverse-order="reverseOrder"
|
:reverse-order="reverseOrder"
|
||||||
:no-padding="noPadding"
|
:no-padding="noPadding"
|
||||||
/>
|
/>
|
||||||
@@ -11,7 +12,8 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { useBreakpoints } from '@vueuse/core'
|
import { breakpointsTailwind, useBreakpoints } from '@vueuse/core'
|
||||||
|
import { computed } from 'vue'
|
||||||
|
|
||||||
import { useTopbarBadgeStore } from '@/stores/topbarBadgeStore'
|
import { useTopbarBadgeStore } from '@/stores/topbarBadgeStore'
|
||||||
|
|
||||||
@@ -28,9 +30,15 @@ withDefaults(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
const BREAKPOINTS = { md: 880 }
|
const breakpoints = useBreakpoints(breakpointsTailwind)
|
||||||
const breakpoints = useBreakpoints(BREAKPOINTS)
|
const isXl = breakpoints.greaterOrEqual('xl')
|
||||||
const notMobile = breakpoints.greater('md')
|
const isLg = breakpoints.greaterOrEqual('lg')
|
||||||
|
|
||||||
|
const displayMode = computed<'full' | 'compact' | 'icon-only'>(() => {
|
||||||
|
if (isXl.value) return 'full'
|
||||||
|
if (isLg.value) return 'compact'
|
||||||
|
return 'icon-only'
|
||||||
|
})
|
||||||
|
|
||||||
const topbarBadgeStore = useTopbarBadgeStore()
|
const topbarBadgeStore = useTopbarBadgeStore()
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
<h2 class="text-2xl">
|
<h2 class="text-2xl">
|
||||||
{{ $t('subscription.title') }}
|
{{ $t('subscription.title') }}
|
||||||
</h2>
|
</h2>
|
||||||
<TopbarBadges reverse-order />
|
<CloudBadge reverse-order />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="grow overflow-auto">
|
<div class="grow overflow-auto">
|
||||||
@@ -196,7 +196,7 @@ import Button from 'primevue/button'
|
|||||||
import TabPanel from 'primevue/tabpanel'
|
import TabPanel from 'primevue/tabpanel'
|
||||||
import { computed, onMounted, ref } from 'vue'
|
import { computed, onMounted, ref } from 'vue'
|
||||||
|
|
||||||
import TopbarBadges from '@/components/topbar/TopbarBadges.vue'
|
import CloudBadge from '@/components/topbar/CloudBadge.vue'
|
||||||
import { useFirebaseAuthActions } from '@/composables/auth/useFirebaseAuthActions'
|
import { useFirebaseAuthActions } from '@/composables/auth/useFirebaseAuthActions'
|
||||||
import SubscribeButton from '@/platform/cloud/subscription/components/SubscribeButton.vue'
|
import SubscribeButton from '@/platform/cloud/subscription/components/SubscribeButton.vue'
|
||||||
import SubscriptionBenefits from '@/platform/cloud/subscription/components/SubscriptionBenefits.vue'
|
import SubscriptionBenefits from '@/platform/cloud/subscription/components/SubscriptionBenefits.vue'
|
||||||
|
|||||||
@@ -25,10 +25,10 @@
|
|||||||
<div class="text-sm text-muted">
|
<div class="text-sm text-muted">
|
||||||
{{ $t('subscription.required.title') }}
|
{{ $t('subscription.required.title') }}
|
||||||
</div>
|
</div>
|
||||||
<TopbarBadges
|
<CloudBadge
|
||||||
reverse-order
|
reverse-order
|
||||||
no-padding
|
no-padding
|
||||||
text-class="!text-sm !font-normal"
|
background-color="var(--p-dialog-background)"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -49,7 +49,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import TopbarBadges from '@/components/topbar/TopbarBadges.vue'
|
import CloudBadge from '@/components/topbar/CloudBadge.vue'
|
||||||
import SubscribeButton from '@/platform/cloud/subscription/components/SubscribeButton.vue'
|
import SubscribeButton from '@/platform/cloud/subscription/components/SubscribeButton.vue'
|
||||||
import SubscriptionBenefits from '@/platform/cloud/subscription/components/SubscriptionBenefits.vue'
|
import SubscriptionBenefits from '@/platform/cloud/subscription/components/SubscriptionBenefits.vue'
|
||||||
import { useSubscription } from '@/platform/cloud/subscription/composables/useSubscription'
|
import { useSubscription } from '@/platform/cloud/subscription/composables/useSubscription'
|
||||||
|
|||||||
Reference in New Issue
Block a user