Skip to content
GitLab
Projects
Groups
Topics
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Register
Sign in
Toggle navigation
Menu
Paulo Avila
petruz-tasks
Commits
36e1afbc
Commit
36e1afbc
authored
Aug 04, 2026
by
Paulo Avila
Browse files
Inclusão de sistema de metas e produção
parent
cfed0f56
Changes
2
Hide whitespace changes
Inline
Side-by-side
src/components/tasks/meta-badge.tsx
0 → 100644
View file @
36e1afbc
import
{
Target
}
from
"
lucide-react
"
;
import
{
getMetaInfo
}
from
"
@/lib/meta
"
;
import
{
Badge
}
from
"
@/components/ui/badge
"
;
import
{
cn
}
from
"
@/lib/utils
"
;
/**
* Indicador da meta de subtarefas em aberto na tarefa-mãe.
* Verde = dentro da meta; vermelho = acima do teto; âmbar = abaixo do piso.
*/
export
function
MetaBadge
({
metaType
,
metaValue
,
subtaskCount
,
subtaskDone
,
className
,
}:
{
metaType
:
string
|
null
;
metaValue
:
number
|
null
;
subtaskCount
:
number
;
subtaskDone
:
number
;
className
?:
string
;
})
{
const
info
=
getMetaInfo
(
metaType
,
metaValue
,
subtaskCount
,
subtaskDone
);
if
(
!
info
)
return
null
;
const
styles
=
{
within
:
"
bg-emerald-500 text-white hover:bg-emerald-500
"
,
exceeded
:
"
bg-destructive text-destructive-foreground hover:bg-destructive
"
,
below
:
"
bg-amber-500 text-white hover:bg-amber-500
"
,
}
as
const
;
return
(
<
Badge
title
=
{
info
.
label
}
className
=
{
cn
(
"
gap-0.5 px-1.5 py-0 text-[10px] font-medium leading-4
"
,
styles
[
info
.
state
],
className
)
}
>
<
Target
className
=
"h-2.5 w-2.5 shrink-0"
/>
{
info
.
shortLabel
}
</
Badge
>
);
}
src/lib/meta.ts
0 → 100644
View file @
36e1afbc
export
type
MetaKind
=
"
teto
"
|
"
piso
"
;
export
type
MetaState
=
"
within
"
|
"
exceeded
"
|
"
below
"
;
export
interface
MetaInfo
{
kind
:
MetaKind
;
state
:
MetaState
;
/** true quando está dentro da meta. */
ok
:
boolean
;
/** Subtarefas em aberto (não concluídas). */
open
:
number
;
/** Valor da meta. */
target
:
number
;
/** Texto completo (tooltip). */
label
:
string
;
/** Texto curto para o badge ("8/10"). */
shortLabel
:
string
;
}
/**
* Avalia a meta de subtarefas em aberto de uma tarefa-mãe recorrente.
* "Em aberto" = subtarefas não concluídas (total − concluídas).
* - teto: dentro quando em aberto ≤ meta; estoura acima.
* - piso: dentro quando em aberto ≥ meta; fica abaixo.
* Retorna null quando a tarefa não usa meta.
*/
export
function
getMetaInfo
(
metaType
:
string
|
null
,
metaValue
:
number
|
null
,
subtaskCount
:
number
,
subtaskDone
:
number
):
MetaInfo
|
null
{
if
((
metaType
!==
"
teto
"
&&
metaType
!==
"
piso
"
)
||
metaValue
==
null
)
{
return
null
;
}
const
open
=
Math
.
max
(
0
,
subtaskCount
-
subtaskDone
);
const
target
=
metaValue
;
if
(
metaType
===
"
teto
"
)
{
const
ok
=
open
<=
target
;
return
{
kind
:
"
teto
"
,
state
:
ok
?
"
within
"
:
"
exceeded
"
,
ok
,
open
,
target
,
label
:
ok
?
`Dentro da meta:
${
open
}
em aberto (teto
${
target
}
)`
:
`Acima da meta:
${
open
}
em aberto (teto
${
target
}
)`
,
shortLabel
:
`
${
open
}
/
${
target
}
`
,
};
}
const
ok
=
open
>=
target
;
return
{
kind
:
"
piso
"
,
state
:
ok
?
"
within
"
:
"
below
"
,
ok
,
open
,
target
,
label
:
ok
?
`Dentro da meta:
${
open
}
em aberto (piso
${
target
}
)`
:
`Abaixo da meta:
${
open
}
em aberto (piso
${
target
}
)`
,
shortLabel
:
`
${
open
}
/
${
target
}
`
,
};
}
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment