Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
77 changes: 42 additions & 35 deletions src/components/DataTable.vue

Large diffs are not rendered by default.

12 changes: 6 additions & 6 deletions src/components/Navbar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,14 @@ const { t } = useI18n()
</script>

<template>
<header class="bg-slate-100 backdrop-blur-xl dark:bg-slate-900">
<header class="sticky top-0 z-30 border-b border-slate-200/80 bg-slate-50/95 backdrop-blur-xl dark:border-slate-800 dark:bg-slate-950/90">
<div class="px-2 sm:px-4 lg:px-6">
<div class="relative flex items-center justify-between h-16 -mb-px">
<!-- Header: Left side -->
<div class="flex items-center space-x-4">
<div v-if="displayStore.NavTitle && isMobile" class="pr-2">
<button
class="flex p-2 rounded-sm dark:text-white focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 focus:outline-none text-slate-500 dark:hover:bg-slate-600 hover:bg-slate-300"
class="inline-flex min-h-11 min-w-11 items-center justify-center rounded-lg text-slate-500 transition-colors hover:bg-slate-200 hover:text-slate-700 focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 focus:outline-none dark:text-slate-200 dark:hover:bg-slate-800 dark:hover:text-white"
:aria-label="t('button-back')"
@click="back()"
>
Expand All @@ -50,7 +50,7 @@ const { t } = useI18n()
</div>
<!-- Hamburger button -->
<button
class="p-1 rounded-md lg:hidden dark:text-white focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 focus:outline-none text-slate-500 dark:hover:text-slate-50 hover:text-slate-600"
class="inline-flex min-h-11 min-w-11 items-center justify-center rounded-lg text-slate-500 transition-colors hover:bg-slate-200 hover:text-slate-700 focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 focus:outline-none dark:text-slate-200 dark:hover:bg-slate-800 dark:hover:text-white lg:hidden"
aria-controls="sidebar"
:aria-expanded="props.sidebarOpen"
:aria-label="props.sidebarOpen ? t('close-sidebar') : t('open-sidebar')"
Expand All @@ -63,14 +63,14 @@ const { t } = useI18n()
<!-- Title on desktop -->
<div class="hidden lg:block">
<div class="flex items-center space-x-2 font-bold truncate md:text-2xl dark:text-white text-md text-dark">
<nav class="text-sm font-normal text-slate-600 dark:text-slate-400" aria-label="Breadcrumb">
<nav class="text-sm font-normal text-slate-600 dark:text-slate-300" aria-label="Breadcrumb">
<ol class="inline-flex items-center space-x-1">
<li v-for="(breadcrumb, i) in displayStore.pathTitle" :key="i" class="flex items-center">
<span v-if="i > 0" class="mx-1" aria-hidden="true"> / </span>
<router-link
:to="breadcrumb.path"
class="px-1 rounded-sm hover:underline focus:ring-2 focus:ring-blue-500 focus:ring-offset-1 focus:outline-none"
:class="i === displayStore.pathTitle.length - 1 ? 'font-bold text-slate-600 dark:text-slate-100' : ''"
class="px-1.5 py-1 rounded-md transition-colors hover:bg-slate-200/70 hover:text-slate-900 focus:ring-2 focus:ring-blue-500 focus:ring-offset-1 focus:outline-none dark:hover:bg-slate-800 dark:hover:text-white"
:class="i === displayStore.pathTitle.length - 1 ? 'font-bold text-slate-800 dark:text-slate-50' : ''"
>
{{ breadcrumb.translate === false ? breadcrumb.name : t(breadcrumb.name) }}
</router-link>
Expand Down
18 changes: 9 additions & 9 deletions src/components/Sidebar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ const tabs = computed<Tab[]>(() => {
<div
class="fixed inset-0 transition-opacity duration-200 lg:hidden z-60"
:class="{
'bg-slate-900/50 cursor-pointer': props.sidebarOpen,
'bg-slate-900/55 cursor-pointer backdrop-blur-sm': props.sidebarOpen,
'bg-slate-900/0 pointer-events-none': !props.sidebarOpen,
}"
aria-hidden="true"
Expand All @@ -102,14 +102,14 @@ const tabs = computed<Tab[]>(() => {
<div
id="sidebar"
ref="sidebar"
class="fixed z-60 left-4 top-16 h-[calc(100%-4rem)] w-64 flex shrink-0 flex-col bg-slate-800 transition-all duration-200 ease-in-out rounded-xl shadow-lg lg:static lg:left-0 lg:top-0 lg:w-64 lg:h-full lg:bg-slate-800 lg:rounded-none lg:shadow-none lg:translate-x-0"
class="fixed z-60 left-4 top-16 h-[calc(100%-4rem)] w-64 flex shrink-0 flex-col bg-slate-800 transition-all duration-200 ease-in-out rounded-xl border border-white/10 shadow-2xl lg:static lg:left-0 lg:top-0 lg:w-64 lg:h-full lg:bg-slate-800 lg:rounded-none lg:border-0 lg:shadow-none lg:translate-x-0"
:class="{
'translate-x-0': props.sidebarOpen,
'-translate-x-[120%]': !props.sidebarOpen,
}"
>
<!-- Sidebar header -->
<div class="flex justify-between px-3 py-4 border-b lg:py-6 lg:px-6 lg:border-b border-slate-800 shrink-0 lg:border-slate-700">
<div class="flex justify-between px-3 py-4 border-b lg:py-6 lg:px-6 lg:border-b border-slate-700/70 shrink-0">
<router-link
class="flex items-center p-1 space-x-2 rounded-lg cursor-pointer lg:space-x-3 focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 focus:outline-none focus:ring-offset-slate-800"
to="/apps"
Expand All @@ -128,24 +128,24 @@ const tabs = computed<Tab[]>(() => {
<!-- Navigation -->
<div class="flex-1 px-3 py-4 space-y-4 overflow-y-auto lg:py-6 lg:px-6">
<div>
<h3 class="mb-3 text-xs font-semibold uppercase lg:mb-4 lg:tracking-wider text-slate-500 lg:text-slate-500">
<h3 class="mb-3 text-xs font-semibold uppercase lg:mb-4 lg:tracking-wider text-slate-400/80">
{{ t('pages') }}
</h3>
<ul class="space-y-1 lg:space-y-2">
<li v-for="tab, i in tabs" :key="i">
<button
class="flex items-center p-3 w-full rounded-md transition duration-150 cursor-pointer lg:p-3 lg:rounded-lg focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 focus:outline-none text-slate-200 min-h-[44px] lg:text-slate-200 lg:hover:bg-slate-700/50 hover:bg-slate-700/50 focus:ring-offset-slate-800"
class="group relative flex min-h-11 w-full items-center overflow-hidden rounded-lg p-3 text-left text-slate-200 transition duration-150 cursor-pointer focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 focus:ring-offset-slate-800 focus:outline-none hover:bg-slate-700/60"
:class="{
'hover:bg-slate-700/50 lg:hover:bg-slate-700/50': !isTabActive(tab.key),
'bg-slate-700 text-white lg:bg-slate-700 lg:text-white': isTabActive(tab.key),
'hover:bg-slate-700/60': !isTabActive(tab.key),
'bg-slate-700/90 text-white shadow-inner before:absolute before:left-0 before:top-2 before:bottom-2 before:w-1 before:rounded-r-full before:bg-sky-300 before:content-[\'\']': isTabActive(tab.key),
'cursor-default': isTabActive(tab.key),
}"
:aria-label="tab.redirect ? `${t(tab.label)} (opens in new tab)` : t(tab.label)"
:aria-current="isTabActive(tab.key) ? 'page' : undefined"
@click="openTab(tab)"
>
<component :is="tab.icon" class="w-5 h-5 transition-colors duration-150 shrink-0" :class="{ 'text-blue-500 lg:text-blue-500': isTabActive(tab.key), 'text-slate-400 group-hover:text-slate-300 lg:text-slate-400 lg:group-hover:text-slate-300': !isTabActive(tab.key) }" />
<span class="flex items-center ml-3 text-sm font-medium capitalize transition-colors duration-150" :class="{ 'text-blue-500 lg:text-blue-500': isTabActive(tab.key), 'text-slate-400 group-hover:text-slate-300 lg:text-slate-400 lg:group-hover:text-slate-300': !isTabActive(tab.key), 'underline': tab.redirect }">
<component :is="tab.icon" class="w-5 h-5 transition-colors duration-150 shrink-0" :class="{ 'text-sky-300': isTabActive(tab.key), 'text-slate-400 group-hover:text-slate-200': !isTabActive(tab.key) }" />
<span class="flex items-center ml-3 text-sm font-medium capitalize transition-colors duration-150" :class="{ 'text-sky-300': isTabActive(tab.key), 'text-slate-300 group-hover:text-white': !isTabActive(tab.key), 'underline': tab.redirect }">
{{ t(tab.label) }}
<svg v-if="tab.redirect" class="w-3 h-3 ml-1 opacity-60" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
<path fill-rule="evenodd" d="M4.25 5.5a.75.75 0 00-.75.75v8.5c0 .414.336.75.75.75h8.5a.75.75 0 00.75-.75v-4a.75.75 0 011.5 0v4A2.25 2.25 0 0112.75 17h-8.5A2.25 2.25 0 012 14.75v-8.5A2.25 2.25 0 014.25 4h5a.75.75 0 010 1.5h-5z" clip-rule="evenodd" />
Expand Down
22 changes: 11 additions & 11 deletions src/components/Tabs.vue
Original file line number Diff line number Diff line change
Expand Up @@ -20,28 +20,28 @@ function activeTabColor(tab: string, isSecondary = false) {
// Secondary row tabs
if (isSecondary) {
return isActive
? 'text-blue-600 dark:text-blue-400 bg-white dark:bg-slate-800 border border-blue-200/70 dark:border-blue-800 shadow-sm hover:ring-1 hover:ring-blue-200 dark:hover:ring-blue-700 hover:bg-blue-50 dark:hover:bg-slate-900 transition-colors'
: 'border border-transparent text-slate-500/75 dark:text-slate-400/75 hover:bg-white dark:hover:bg-slate-900 hover:text-slate-700 dark:hover:text-slate-200 transition-colors'
? 'text-blue-700 dark:text-blue-300 bg-white dark:bg-slate-900 border border-blue-200/80 dark:border-blue-800 shadow-sm ring-1 ring-blue-100/70 dark:ring-blue-900/40 hover:bg-white dark:hover:bg-slate-900 transition-colors'
: 'border border-transparent text-slate-500 dark:text-slate-400 hover:bg-white/80 dark:hover:bg-slate-900 hover:text-slate-800 dark:hover:text-slate-100 transition-colors'
}

// Primary row tabs - open tab style
return isActive
? 'text-blue-500 dark:text-blue-300 bg-blue-50 dark:bg-slate-800/40 border-t border-l border-r border-blue-200/60 dark:border-blue-800/70 border-b-0 before:content-[\'\'] before:absolute before:bottom-[-1px] before:left-0 before:right-0 before:h-[3px] before:bg-blue-50 dark:before:bg-[#141e33] before:z-[11] hover:bg-blue-100 dark:hover:bg-[#1e3050] transition-colors'
: 'border border-transparent text-slate-500/75 dark:text-slate-400/75 hover:bg-blue-100/70 dark:hover:bg-[#1a2744cc] hover:text-slate-700 dark:hover:text-slate-200 transition-colors'
? 'text-blue-700 dark:text-blue-300 bg-white dark:bg-slate-900 border-t border-l border-r border-blue-200/80 dark:border-blue-800/80 border-b-0 shadow-sm before:content-[\'\'] before:absolute before:bottom-[-1px] before:left-0 before:right-0 before:h-[3px] before:bg-white dark:before:bg-slate-900 before:z-[11] hover:bg-white dark:hover:bg-slate-900 transition-colors'
: 'border border-transparent text-slate-500 dark:text-slate-400 hover:bg-white/70 dark:hover:bg-slate-900/80 hover:text-slate-800 dark:hover:text-slate-100 transition-colors'
}

const ulPrimaryClass = 'flex text-xs md:text-sm font-medium text-center text-gray-500 dark:text-gray-300 gap-1 pt-1 px-1'
const ulSecondaryClass = 'flex text-sm font-medium text-center text-gray-600 dark:text-gray-200 gap-2 py-2'
const buttonPrimaryClass = 'inline-flex items-center gap-2 px-3 py-2 min-w-[42px] min-h-[38px] rounded-t-md cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2 focus-visible:ring-offset-slate-50 dark:focus-visible:ring-offset-slate-900 transition-all group relative'
const buttonSecondaryClass = 'inline-flex items-center gap-2 px-3 py-1.5 rounded-md cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2 focus-visible:ring-offset-slate-50 dark:focus-visible:ring-offset-slate-900 transition-colors group'
const ulPrimaryClass = 'flex text-xs md:text-sm font-medium text-center text-gray-500 dark:text-gray-300 gap-1.5 pt-2 px-2'
const ulSecondaryClass = 'flex text-sm font-medium text-center text-gray-600 dark:text-gray-200 gap-2 py-2 px-2'
const buttonPrimaryClass = 'inline-flex items-center gap-2 px-3.5 py-2 min-w-11 min-h-11 rounded-t-lg cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2 focus-visible:ring-offset-slate-50 dark:focus-visible:ring-offset-slate-900 transition-all group relative'
const buttonSecondaryClass = 'inline-flex items-center gap-2 px-3.5 py-2 min-h-11 rounded-lg cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2 focus-visible:ring-offset-slate-50 dark:focus-visible:ring-offset-slate-900 transition-colors group'
const iconClass = 'w-5 h-5 transition-colors'
const labelClass = 'hidden md:block text-xs md:text-sm font-medium transition-colors first-letter:uppercase'
</script>

<template>
<div>
<div class="pb-0">
<ul :class="[ulPrimaryClass, noWrap ? 'flex-nowrap overflow-x-scroll no-scrollbar px-1' : 'flex-wrap']">
<ul :class="[ulPrimaryClass, noWrap ? 'flex-nowrap overflow-x-auto no-scrollbar' : 'flex-wrap']">
<li v-for="(tab, i) in tabs" :key="i" class="relative mr-2" :class="{ 'z-20': activeTab === tab.key }">
<button :class="[buttonPrimaryClass, activeTabColor(tab.key)]" @click="emit('update:activeTab', tab.key)">
<component :is="tab.icon" :class="iconClass" />
Expand All @@ -50,8 +50,8 @@ const labelClass = 'hidden md:block text-xs md:text-sm font-medium transition-co
</li>
</ul>
</div>
<div class="relative -mt-px border-t bg-blue-50 dark:bg-slate-800/40 border-blue-200/60 dark:border-blue-800/70" :class="secondaryTabs?.length ? 'z-10' : 'z-0'">
<ul v-if="secondaryTabs?.length" :class="[ulSecondaryClass, noWrap ? 'flex-nowrap overflow-x-scroll no-scrollbar px-1' : 'flex-wrap']">
<div class="relative -mt-px border-t bg-slate-50/95 dark:bg-slate-950/40 border-blue-200/60 dark:border-blue-800/70" :class="secondaryTabs?.length ? 'z-10' : 'z-0'">
<ul v-if="secondaryTabs?.length" :class="[ulSecondaryClass, noWrap ? 'flex-nowrap overflow-x-auto no-scrollbar' : 'flex-wrap']">
<li v-for="(tab, i) in secondaryTabs" :key="i" class="mr-2">
<button :class="[buttonSecondaryClass, activeTabColor(tab.key, true)]" @click="emit('update:secondaryActiveTab', tab.key)">
<component :is="tab.icon" :class="iconClass" />
Expand Down
9 changes: 4 additions & 5 deletions src/components/auth/AuthPageShell.vue
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,7 @@ const heroHighlights = computed(() => props.heroHighlights ?? [
class="relative flex h-dvh min-h-dvh w-full overflow-y-auto bg-[linear-gradient(180deg,rgba(248,250,252,0.98)_0%,rgba(238,244,255,0.9)_55%,rgba(248,250,252,0.98)_100%)] dark:bg-[linear-gradient(180deg,rgba(15,23,42,0.98)_0%,rgba(20,29,53,0.96)_52%,rgba(15,23,42,0.98)_100%)]"
>
<div class="pointer-events-none absolute inset-0 hidden overflow-hidden lg:block" aria-hidden="true">
<div class="absolute top-[10%] -left-32 h-[22rem] w-[22rem] rounded-full bg-[rgba(17,158,255,0.22)] opacity-55 blur-[52px]" />
<div class="absolute right-[-7rem] bottom-[8%] h-[18rem] w-[18rem] rounded-full bg-[rgba(104,118,225,0.18)] opacity-55 blur-[52px]" />
<div class="absolute inset-0 bg-[radial-gradient(ellipse_at_top,rgba(17,158,255,0.13)_0%,transparent_44%)]" />
<div
class="absolute inset-0 opacity-40 [background-image:linear-gradient(rgba(148,163,184,0.12)_1px,transparent_1px),linear-gradient(90deg,rgba(148,163,184,0.12)_1px,transparent_1px)] [background-size:3rem_3rem] [mask-image:radial-gradient(circle_at_center,black_40%,transparent_82%)]"
/>
Expand All @@ -82,7 +81,7 @@ const heroHighlights = computed(() => props.heroHighlights ?? [
</div>

<div class="mt-8 space-y-5">
<div class="inline-flex h-14 w-14 items-center justify-center rounded-2xl border border-slate-200/70 bg-white/80 shadow-lg shadow-slate-900/5 backdrop-blur dark:border-slate-700/80 dark:bg-slate-900/70">
<div class="inline-flex h-14 w-14 items-center justify-center rounded-xl border border-slate-200/70 bg-white/80 shadow-lg shadow-slate-900/5 backdrop-blur dark:border-slate-700/80 dark:bg-slate-900/70">
<img src="/capgo.webp" alt="Capgo logo" class="h-8 w-8 rounded-sm invert dark:invert-0">
</div>
<div>
Expand All @@ -102,7 +101,7 @@ const heroHighlights = computed(() => props.heroHighlights ?? [
<article
v-for="highlight in heroHighlights"
:key="highlight.title"
class="rounded-3xl border border-white/70 bg-white/78 p-5 shadow-[0_20px_50px_-30px_rgba(15,23,42,0.45)] backdrop-blur dark:border-slate-700/70 dark:bg-slate-900/72"
class="rounded-2xl border border-white/70 bg-white/78 p-5 shadow-[0_20px_50px_-34px_rgba(15,23,42,0.45)] backdrop-blur dark:border-slate-700/70 dark:bg-slate-900/72"
>
<div class="mb-3 h-2 w-12 rounded-full bg-gradient-to-r from-sky-500 via-sky-400 to-indigo-500" />
<h2 class="text-base font-semibold text-slate-900 dark:text-white">
Expand Down Expand Up @@ -131,7 +130,7 @@ const heroHighlights = computed(() => props.heroHighlights ?? [
</div>
</div>

<div class="rounded-none border-0 bg-transparent p-0 shadow-none backdrop-blur-0 sm:rounded-[1.75rem] sm:border sm:border-slate-200/75 sm:bg-[linear-gradient(180deg,rgba(255,255,255,0.94)_0%,rgba(255,255,255,0.84)_100%)] sm:p-7 sm:shadow-[0_34px_80px_-42px_rgba(15,23,42,0.5)] sm:backdrop-blur-[18px] sm:dark:border-slate-600/70 sm:dark:bg-[linear-gradient(180deg,rgba(15,23,42,0.88)_0%,rgba(15,23,42,0.7)_100%)]">
<div class="rounded-none border-0 bg-transparent p-0 shadow-none backdrop-blur-0 sm:rounded-2xl sm:border sm:border-slate-200/80 sm:bg-[linear-gradient(180deg,rgba(255,255,255,0.96)_0%,rgba(255,255,255,0.88)_100%)] sm:p-7 sm:shadow-[0_30px_70px_-46px_rgba(15,23,42,0.52)] sm:backdrop-blur-[18px] sm:dark:border-slate-600/70 sm:dark:bg-[linear-gradient(180deg,rgba(15,23,42,0.9)_0%,rgba(15,23,42,0.74)_100%)]">
<div class="flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between">
<div>
<p v-if="cardKicker" class="text-[0.72rem] font-bold tracking-[0.22em] text-slate-500 uppercase dark:text-slate-400">
Expand Down
6 changes: 3 additions & 3 deletions src/components/dashboard/ChartCard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ const displayNoDataMessage = computed(() => props.noDataMessage ?? t('no-data'))
</script>

<template>
<div class="relative col-span-full flex h-[460px] flex-col overflow-hidden rounded-[1.75rem] border border-slate-200/80 bg-white/95 shadow-[0_20px_60px_-38px_rgba(15,23,42,0.3)] backdrop-blur dark:border-slate-700/70 dark:bg-slate-900/85 dark:shadow-[0_24px_70px_-42px_rgba(2,6,23,0.72)]">
<div class="pointer-events-none absolute inset-x-0 top-0 h-28 bg-gradient-to-br from-slate-50 via-white to-transparent dark:from-slate-800/70 dark:via-slate-900/40 dark:to-transparent" />
<div class="relative col-span-full flex h-[460px] flex-col overflow-hidden rounded-2xl border border-slate-200/90 bg-white shadow-[0_18px_48px_-38px_rgba(15,23,42,0.45)] dark:border-slate-700/80 dark:bg-slate-900 dark:shadow-[0_24px_70px_-48px_rgba(2,6,23,0.82)]">
<div class="pointer-events-none absolute inset-x-0 top-0 h-24 bg-gradient-to-br from-slate-50 via-white to-transparent dark:from-slate-800/70 dark:via-slate-900/40 dark:to-transparent" />

<!-- Header with title and stats -->
<div class="relative overflow-hidden px-5 pt-5">
Expand All @@ -71,7 +71,7 @@ const displayNoDataMessage = computed(() => props.noDataMessage ?? t('no-data'))
<div
v-if="showEvolutionBadge"
class="inline-flex justify-center items-center rounded-full px-3 py-1 text-xs font-bold text-white shadow-sm"
:class="{ 'bg-cyan-500': (lastDayEvolution ?? 0) >= 0, 'bg-amber-500': (lastDayEvolution ?? 0) < 0 }"
:class="{ 'bg-cyan-600': (lastDayEvolution ?? 0) >= 0, 'bg-amber-600': (lastDayEvolution ?? 0) < 0 }"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Increase badge contrast for accessibility.

On Line 74, bg-cyan-600 / bg-amber-600 with text-white at text-xs likely remains below WCAG AA contrast for normal text. Please use darker badge backgrounds (or darker text) to keep the evolution value readable.

Proposed patch
-              :class="{ 'bg-cyan-600': (lastDayEvolution ?? 0) >= 0, 'bg-amber-600': (lastDayEvolution ?? 0) < 0 }"
+              :class="{ 'bg-cyan-700': (lastDayEvolution ?? 0) >= 0, 'bg-amber-700': (lastDayEvolution ?? 0) < 0 }"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
:class="{ 'bg-cyan-600': (lastDayEvolution ?? 0) >= 0, 'bg-amber-600': (lastDayEvolution ?? 0) < 0 }"
:class="{ 'bg-cyan-700': (lastDayEvolution ?? 0) >= 0, 'bg-amber-700': (lastDayEvolution ?? 0) < 0 }"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/dashboard/ChartCard.vue` at line 74, The badge's dynamic class
binding using 'bg-cyan-600' / 'bg-amber-600' for the element that shows
lastDayEvolution doesn't meet WCAG contrast; update the class binding in
ChartCard.vue (the expression referencing lastDayEvolution) to use darker
background colors (e.g., 'bg-cyan-800' and 'bg-amber-800') or switch to a
high-contrast text color (e.g., add 'text-black' instead of 'text-white') and
optionally increase weight/size (e.g., 'font-semibold') so the evolution value
meets accessibility contrast requirements.

>
{{ (lastDayEvolution ?? 0) < 0 ? '-' : '+' }}{{ Math.abs(lastDayEvolution ?? 0).toFixed(2) }}%
</div>
Expand Down
Loading
Loading