Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Q
qjclaw-dmg
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
AI-甘富林
qjclaw-dmg
Commits
286f1972
Commit
286f1972
authored
May 14, 2026
by
edy
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fix(ui): refine task panel layout
parent
6acc6e51
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
381 additions
and
121 deletions
+381
-121
TaskPanelView.tsx
apps/ui/src/features/tasks/TaskPanelView.tsx
+107
-9
tasks.css
apps/ui/src/styles/tasks.css
+274
-112
No files found.
apps/ui/src/features/tasks/TaskPanelView.tsx
View file @
286f1972
import
{
useEffect
,
useMemo
,
useRef
,
useState
}
from
"react"
import
{
useCallback
,
useEffect
,
useMemo
,
useRef
,
useState
}
from
"react"
import
{
createPortal
}
from
"react-dom"
import
type
{
TaskPanelArtifact
,
TaskPanelItem
,
TaskPanelStatus
}
from
"@qjclaw/shared-types"
import
{
renderExpertIcon
}
from
"../../components/icons/AppIcons"
import
{
Panel
}
from
"../../components/ui/Panel"
...
...
@@ -114,7 +115,10 @@ function TaskArtifactList({
function
TaskArtifacts
({
item
}:
{
item
:
TaskPanelItem
})
{
const
[
copiedArtifactId
,
setCopiedArtifactId
]
=
useState
(
""
)
const
[
isMenuOpen
,
setIsMenuOpen
]
=
useState
(
false
)
const
[
popoverPosition
,
setPopoverPosition
]
=
useState
<
{
top
:
number
;
left
:
number
;
width
:
number
;
maxHeight
:
number
}
|
null
>
(
null
)
const
menuRef
=
useRef
<
HTMLDivElement
|
null
>
(
null
)
const
triggerRef
=
useRef
<
HTMLButtonElement
|
null
>
(
null
)
const
popoverRef
=
useRef
<
HTMLDivElement
|
null
>
(
null
)
const
copiedTimerRef
=
useRef
<
number
|
null
>
(
null
)
useEffect
(()
=>
{
...
...
@@ -125,6 +129,27 @@ function TaskArtifacts({ item }: { item: TaskPanelItem }) {
}
},
[])
const
updatePopoverPosition
=
useCallback
(()
=>
{
const
triggerElement
=
triggerRef
.
current
if
(
!
triggerElement
)
{
return
}
const
margin
=
16
const
gap
=
8
const
triggerRect
=
triggerElement
.
getBoundingClientRect
()
const
width
=
Math
.
min
(
520
,
Math
.
max
(
280
,
window
.
innerWidth
-
margin
*
2
))
const
left
=
Math
.
min
(
Math
.
max
(
triggerRect
.
left
,
margin
),
window
.
innerWidth
-
width
-
margin
)
const
belowTop
=
triggerRect
.
bottom
+
gap
const
spaceBelow
=
window
.
innerHeight
-
belowTop
-
margin
const
spaceAbove
=
triggerRect
.
top
-
margin
-
gap
const
preferBelow
=
spaceBelow
>=
160
||
spaceBelow
>=
spaceAbove
const
maxHeight
=
Math
.
min
(
220
,
Math
.
max
(
140
,
preferBelow
?
spaceBelow
:
spaceAbove
))
const
top
=
preferBelow
?
belowTop
:
Math
.
max
(
margin
,
triggerRect
.
top
-
gap
-
maxHeight
)
setPopoverPosition
({
top
,
left
,
width
,
maxHeight
})
},
[])
useEffect
(()
=>
{
setIsMenuOpen
(
false
)
setCopiedArtifactId
(
""
)
...
...
@@ -137,7 +162,12 @@ function TaskArtifacts({ item }: { item: TaskPanelItem }) {
const
handlePointerDown
=
(
event
:
PointerEvent
)
=>
{
const
menuElement
=
menuRef
.
current
if
(
menuElement
&&
event
.
target
instanceof
Node
&&
!
menuElement
.
contains
(
event
.
target
))
{
const
popoverElement
=
popoverRef
.
current
if
(
event
.
target
instanceof
Node
&&
!
menuElement
?.
contains
(
event
.
target
)
&&
!
popoverElement
?.
contains
(
event
.
target
)
)
{
setIsMenuOpen
(
false
)
}
}
...
...
@@ -157,6 +187,21 @@ function TaskArtifacts({ item }: { item: TaskPanelItem }) {
}
},
[
isMenuOpen
])
useEffect
(()
=>
{
if
(
!
isMenuOpen
)
{
return
}
updatePopoverPosition
()
window
.
addEventListener
(
"resize"
,
updatePopoverPosition
)
window
.
addEventListener
(
"scroll"
,
updatePopoverPosition
,
true
)
return
()
=>
{
window
.
removeEventListener
(
"resize"
,
updatePopoverPosition
)
window
.
removeEventListener
(
"scroll"
,
updatePopoverPosition
,
true
)
}
},
[
isMenuOpen
,
updatePopoverPosition
])
const
copyArtifactUrl
=
async
(
artifactId
:
string
,
artifactUrl
:
string
)
=>
{
try
{
await
navigator
.
clipboard
.
writeText
(
artifactUrl
)
...
...
@@ -196,24 +241,57 @@ function TaskArtifacts({ item }: { item: TaskPanelItem }) {
return
(
<
div
className=
"task-panel-artifact-menu"
ref=
{
menuRef
}
>
<
button
ref=
{
triggerRef
}
type=
"button"
className=
"task-panel-artifact-trigger"
aria
-
haspopup=
"menu"
aria
-
expanded=
{
isMenuOpen
}
aria
-
controls=
{
item
.
id
+
"-artifact-menu"
}
onClick=
{
()
=>
setIsMenuOpen
((
current
)
=>
!
current
)
}
onClick=
{
()
=>
{
if
(
!
isMenuOpen
)
{
updatePopoverPosition
()
}
setIsMenuOpen
((
current
)
=>
!
current
)
}
}
>
{
item
.
artifacts
.
length
}
个产物
</
button
>
{
isMenuOpen
?
(
<
div
className=
"task-panel-artifact-popover"
id=
{
item
.
id
+
"-artifact-menu"
}
role=
"menu"
>
{
isMenuOpen
&&
popoverPosition
?
createPortal
((
<
div
ref=
{
popoverRef
}
className=
"task-panel-artifact-popover"
id=
{
item
.
id
+
"-artifact-menu"
}
role=
"menu"
style=
{
{
top
:
popoverPosition
.
top
,
left
:
popoverPosition
.
left
,
width
:
popoverPosition
.
width
,
maxHeight
:
popoverPosition
.
maxHeight
}
}
>
<
TaskArtifactList
artifacts=
{
item
.
artifacts
}
copiedArtifactId=
{
copiedArtifactId
}
onCopy=
{
(
artifactId
,
artifactUrl
)
=>
void
copyArtifactUrl
(
artifactId
,
artifactUrl
)
}
/>
</
div
>
)
:
null
}
),
document
.
body
)
:
null
}
</
div
>
)
}
function
TaskPanelLoadingState
()
{
return
(
<
div
className=
"task-panel-loading-state"
role=
"status"
aria
-
label=
"任务列表加载中"
>
{
Array
.
from
({
length
:
4
},
(
_
,
index
)
=>
(
<
div
className=
"task-panel-loading-row"
key=
{
index
}
aria
-
hidden=
"true"
>
<
span
className=
"task-panel-loading-avatar"
/>
<
span
className=
"task-panel-loading-line task-panel-loading-line-name"
/>
<
span
className=
"task-panel-loading-line task-panel-loading-line-task"
/>
<
span
className=
"task-panel-loading-pill"
/>
<
span
className=
"task-panel-loading-line task-panel-loading-line-artifact"
/>
</
div
>
))
}
</
div
>
)
}
...
...
@@ -224,8 +302,27 @@ export function TaskPanelView() {
const
[
selectedTaskIds
,
setSelectedTaskIds
]
=
useState
<
Record
<
string
,
string
>>
({})
const
[
loading
,
setLoading
]
=
useState
(
true
)
const
[
errorText
,
setErrorText
]
=
useState
(
""
)
const
[
greetingText
,
setGreetingText
]
=
useState
(
""
)
const
dateInputRef
=
useRef
<
HTMLInputElement
|
null
>
(
null
)
useEffect
(()
=>
{
const
greeting
=
"Hi,今日任务请查收~"
let
index
=
0
setGreetingText
(
""
)
const
timer
=
window
.
setInterval
(()
=>
{
index
+=
1
setGreetingText
(
greeting
.
slice
(
0
,
index
))
if
(
index
>=
greeting
.
length
)
{
window
.
clearInterval
(
timer
)
}
},
42
)
return
()
=>
{
window
.
clearInterval
(
timer
)
}
},
[])
useEffect
(()
=>
{
let
active
=
true
setLoading
(
true
)
...
...
@@ -278,7 +375,8 @@ export function TaskPanelView() {
<
Panel
className=
"task-panel-page"
bodyClassName=
"task-panel-body"
>
<
div
className=
"task-panel-header"
>
<
div
className=
"task-panel-title-group"
>
<
h1
><
span
>
任务面板
</
span
></
h1
>
<
h1
className=
"task-panel-heading"
>
任务面板
</
h1
>
<
p
className=
"task-panel-greeting"
aria
-
label=
"任务面板问候语"
>
{
greetingText
}
</
p
>
</
div
>
<
div
className=
"task-panel-date-field"
>
<
button
...
...
@@ -315,7 +413,7 @@ export function TaskPanelView() {
</
div
>
<
ScrollArea
className=
"scroll-panel task-panel-scroll"
aria
-
busy=
{
loading
}
>
{
loading
?
<
div
className=
"empty-state task-panel-state"
>
任务列表加载中...
</
div
>
:
null
}
{
loading
?
<
TaskPanelLoadingState
/
>
:
null
}
{
!
loading
&&
errorText
?
<
div
className=
"notice error task-panel-state"
role=
"alert"
>
{
errorText
}
</
div
>
:
null
}
{
!
loading
&&
!
errorText
&&
!
items
.
length
?
<
div
className=
"empty-state task-panel-state"
>
当天暂无任务
</
div
>
:
null
}
{
!
loading
&&
!
errorText
&&
items
.
length
?
(
...
...
@@ -348,7 +446,7 @@ export function TaskPanelView() {
}
}
>
{
row
.
tasks
.
map
((
task
)
=>
(
<
option
key=
{
task
.
id
}
value=
{
task
.
id
}
>
{
task
.
taskTitle
}
</
option
>
<
option
key=
{
task
.
id
}
title=
{
task
.
taskTitle
}
value=
{
task
.
id
}
>
{
task
.
taskTitle
}
</
option
>
))
}
</
select
>
</
div
>
...
...
apps/ui/src/styles/tasks.css
View file @
286f1972
...
...
@@ -7,18 +7,18 @@
.task-panel-page
{
flex
:
1
;
min-height
:
0
;
padding
:
22
px
;
padding
:
18
px
;
overflow
:
hidden
;
border-radius
:
2
8
px
;
border-radius
:
2
2
px
;
border
:
1px
solid
var
(
--ui-color-border
);
background
:
linear-gradient
(
180deg
,
rgba
(
255
,
255
,
255
,
0.98
),
rgba
(
248
,
25
2
,
251
,
0.96
));
box-shadow
:
var
(
--ui-shadow-panel
);
background
:
linear-gradient
(
180deg
,
rgba
(
255
,
255
,
255
,
0.98
),
rgba
(
248
,
25
0
,
252
,
0.96
));
box-shadow
:
0
16px
36px
rgba
(
15
,
23
,
42
,
0.07
);
}
.task-panel-body
{
display
:
grid
;
grid-template-rows
:
auto
minmax
(
0
,
1
fr
);
gap
:
1
6
px
;
gap
:
1
2
px
;
min-height
:
0
;
height
:
100%
;
padding
:
0
;
...
...
@@ -26,10 +26,11 @@
.task-panel-header
{
display
:
flex
;
align-items
:
center
;
align-items
:
flex-end
;
justify-content
:
space-between
;
gap
:
1
6
px
;
gap
:
1
4
px
;
min-width
:
0
;
padding
:
0
2px
2px
;
}
.task-panel-title-group
{
...
...
@@ -37,32 +38,36 @@
min-width
:
0
;
}
.task-panel-title-group
h1
{
display
:
inline-flex
;
width
:
fit-content
;
margin
:
0
;
padding
:
4px
;
border-radius
:
999px
;
border
:
1px
solid
rgba
(
191
,
219
,
254
,
0.92
);
background
:
linear-gradient
(
180deg
,
#ffffff
0%
,
#eef7ff
100%
);
box-shadow
:
0
10px
22px
rgba
(
37
,
99
,
235
,
0.1
),
inset
0
1px
0
rgba
(
255
,
255
,
255
,
0.96
);
color
:
#1d344f
;
font-size
:
18px
;
line-height
:
1.2
;
.task-panel-heading
{
position
:
absolute
;
width
:
1px
;
height
:
1px
;
overflow
:
hidden
;
clip
:
rect
(
0
0
0
0
);
white-space
:
nowrap
;
}
.task-panel-title-group
h1
span
{
display
:
inline-flex
;
min-height
:
36px
;
align-items
:
center
;
padding
:
0
18px
;
border-radius
:
999px
;
background
:
#ffffff
;
box-shadow
:
inset
0
0
0
1px
rgba
(
226
,
232
,
240
,
0.9
);
font-weight
:
800
;
.task-panel-greeting
{
margin
:
0
;
color
:
#334155
;
font-size
:
15px
;
font-weight
:
650
;
line-height
:
1.35
;
letter-spacing
:
0
;
white-space
:
nowrap
;
}
.task-panel-greeting
::after
{
content
:
""
;
display
:
inline-block
;
width
:
8px
;
height
:
1.08em
;
margin-left
:
2px
;
vertical-align
:
-0.12em
;
background
:
linear-gradient
(
180deg
,
rgba
(
37
,
99
,
235
,
0.72
),
rgba
(
59
,
130
,
246
,
0.18
));
animation
:
task-panel-greeting-caret
0.9s
steps
(
1
,
end
)
infinite
;
}
.task-panel-date-field
{
position
:
relative
;
display
:
inline-grid
;
...
...
@@ -82,8 +87,8 @@
.task-panel-header
.task-panel-date-pill
{
display
:
inline-flex
;
align-items
:
center
;
gap
:
8
px
;
min-height
:
42
px
;
gap
:
7
px
;
min-height
:
36
px
;
padding
:
0
;
border
:
0
;
border-radius
:
0
;
...
...
@@ -110,11 +115,11 @@
.task-panel-date-calendar
{
display
:
grid
;
grid-template-rows
:
10px
1
fr
;
width
:
3
2
px
;
height
:
3
2
px
;
width
:
3
0
px
;
height
:
3
0
px
;
overflow
:
hidden
;
place-items
:
center
;
border-radius
:
9
px
;
border-radius
:
8
px
;
background
:
linear-gradient
(
180deg
,
#ffffff
0%
,
#eef4ff
100%
);
border
:
1px
solid
#d7e1ef
;
box-shadow
:
inset
0
1px
0
rgba
(
255
,
255
,
255
,
0.94
),
0
5px
10px
rgba
(
15
,
23
,
42
,
0.08
);
...
...
@@ -134,22 +139,22 @@
.task-panel-date-calendar-day
{
color
:
#1f2f49
;
font-size
:
1
2
px
;
font-size
:
1
1
px
;
font-weight
:
800
;
line-height
:
1
;
}
.task-panel-date-value
{
display
:
inline-flex
;
min-height
:
42
px
;
min-height
:
36
px
;
align-items
:
center
;
padding
:
0
1
6
px
;
padding
:
0
1
3
px
;
border
:
1px
solid
rgba
(
203
,
213
,
225
,
0.92
);
border-radius
:
999px
;
background
:
linear-gradient
(
180deg
,
#ffffff
0%
,
#f8fbff
100%
);
box-shadow
:
none
;
font-size
:
1
4
px
;
font-weight
:
8
00
;
font-size
:
1
3
px
;
font-weight
:
7
00
;
line-height
:
1
;
white-space
:
nowrap
;
}
...
...
@@ -162,46 +167,62 @@
.task-panel-scroll
{
min-height
:
0
;
padding-right
:
4
px
;
padding-right
:
2
px
;
}
.task-panel-state
{
padding
:
20px
;
display
:
grid
;
min-height
:
220px
;
place-items
:
center
;
padding
:
28px
;
border-radius
:
14px
;
color
:
#64748b
;
font-size
:
13px
;
font-weight
:
600
;
background
:
linear-gradient
(
180deg
,
rgba
(
248
,
251
,
255
,
0.96
),
rgba
(
255
,
255
,
255
,
0.96
));
border-color
:
rgba
(
203
,
213
,
225
,
0.82
);
}
.task-panel-table
{
display
:
grid
;
gap
:
8
px
;
min-width
:
92
0px
;
gap
:
6
px
;
min-width
:
86
0px
;
}
.task-panel-row
{
display
:
grid
;
grid-template-columns
:
1
65px
225px
170px
minmax
(
25
0px
,
1
fr
);
gap
:
1
4
px
;
grid-template-columns
:
1
50px
150px
138px
minmax
(
28
0px
,
1
fr
);
gap
:
1
2
px
;
align-items
:
center
;
min-height
:
104px
;
max-height
:
104px
;
padding
:
14px
16px
;
min-height
:
82px
;
padding
:
12px
14px
;
overflow
:
visible
;
border-radius
:
16px
;
border
:
1px
solid
rgba
(
215
,
216
,
229
,
0.96
);
background
:
rgba
(
255
,
255
,
255
,
0.92
);
box-shadow
:
0
12px
28px
rgba
(
17
,
24
,
39
,
0.04
);
border-radius
:
12px
;
border
:
1px
solid
rgba
(
226
,
232
,
240
,
0.96
);
background
:
rgba
(
255
,
255
,
255
,
0.88
);
box-shadow
:
0
8px
18px
rgba
(
15
,
23
,
42
,
0.035
);
transition
:
border-color
160ms
ease
,
background
160ms
ease
,
box-shadow
160ms
ease
,
transform
160ms
ease
;
}
.task-panel-row-head
{
min-height
:
44px
;
max-height
:
44px
;
min-height
:
36px
;
align-items
:
center
;
text-align
:
center
;
padding
:
10px
16px
;
padding
:
8px
14px
;
overflow
:
hidden
;
border-radius
:
1
4
px
;
background
:
rgba
(
2
39
,
246
,
255
,
0.78
);
color
:
#
53637f
;
border-radius
:
1
0
px
;
background
:
rgba
(
2
48
,
250
,
252
,
0.92
);
color
:
#
64748b
;
font-size
:
12px
;
font-weight
:
800
;
font-weight
:
700
;
box-shadow
:
none
;
}
.task-panel-row
:not
(
.task-panel-row-head
)
:hover
,
.task-panel-row
:not
(
.task-panel-row-head
)
:focus-within
{
border-color
:
rgba
(
147
,
197
,
253
,
0.86
);
background
:
#ffffff
;
box-shadow
:
0
12px
26px
rgba
(
15
,
23
,
42
,
0.07
);
transform
:
translateY
(
-1px
);
}
.task-panel-row
>
div
{
...
...
@@ -209,20 +230,20 @@
}
.task-panel-row
:not
(
.task-panel-row-head
)
>
div
:nth-child
(
3
)
{
padding-left
:
5
4px
;
padding-left
:
1
4px
;
}
.task-panel-row
:not
(
.task-panel-row-head
)
>
div
:nth-child
(
4
)
{
display
:
flex
;
position
:
relative
;
align-items
:
center
;
justify-content
:
center
;
justify-content
:
flex-start
;
padding-left
:
0
;
}
.task-panel-expert-cell
{
display
:
grid
;
grid-template-columns
:
3
6
px
minmax
(
0
,
1
fr
);
grid-template-columns
:
3
2
px
minmax
(
0
,
1
fr
);
align-items
:
center
;
gap
:
10px
;
min-width
:
0
;
...
...
@@ -230,18 +251,18 @@
.task-panel-expert-icon
{
display
:
grid
;
width
:
3
6
px
;
height
:
3
6
px
;
width
:
3
2
px
;
height
:
3
2
px
;
place-items
:
center
;
border-radius
:
1
2
px
;
border-radius
:
1
0
px
;
color
:
#2563eb
;
background
:
#eff6ff
;
border
:
1px
solid
#dbeafe
;
}
.task-panel-expert-icon
svg
{
width
:
21
px
;
height
:
21
px
;
width
:
19
px
;
height
:
19
px
;
}
.task-panel-expert-icon-planner
{
...
...
@@ -272,7 +293,7 @@
min-width
:
0
;
color
:
#1c324d
;
font-size
:
13px
;
font-weight
:
50
0
;
font-weight
:
65
0
;
line-height
:
1.4
;
overflow
:
hidden
;
text-overflow
:
ellipsis
;
...
...
@@ -280,23 +301,38 @@
}
.task-panel-task-cell
{
display
:
flex
;
min-width
:
0
;
}
.task-panel-task-cell
select
{
width
:
100%
;
width
:
10em
;
max-width
:
100%
;
min-width
:
0
;
min-height
:
3
8
px
;
min-height
:
3
4
px
;
padding
:
0
34px
0
12px
;
border-radius
:
1
2
px
;
border-radius
:
1
0
px
;
border
:
1px
solid
#d8e1ef
;
background
:
#f
fffff
;
background
:
#f
8fafc
;
color
:
#1f2f49
;
font
:
inherit
;
font-size
:
13px
;
overflow
:
hidden
;
text-overflow
:
ellipsis
;
white-space
:
nowrap
;
cursor
:
pointer
;
transition
:
border-color
160ms
ease
,
background
160ms
ease
,
box-shadow
160ms
ease
;
}
.task-panel-task-cell
select
:hover
,
.task-panel-task-cell
select
:focus-visible
{
border-color
:
#93c5fd
;
background
:
#ffffff
;
}
.task-panel-task-cell
select
:focus-visible
{
outline
:
2px
solid
rgba
(
37
,
99
,
235
,
0.26
);
outline-offset
:
2px
;
}
.task-panel-status
{
...
...
@@ -309,8 +345,8 @@
.task-panel-status-icon
{
display
:
grid
;
flex
:
0
0
auto
;
width
:
34
px
;
height
:
2
8
px
;
width
:
28
px
;
height
:
2
4
px
;
place-items
:
center
;
border-radius
:
999px
;
font-size
:
13px
;
...
...
@@ -321,8 +357,8 @@
.task-panel-status-text
{
min-width
:
0
;
color
:
#1f2f49
;
font-size
:
1
3
px
;
font-weight
:
6
0
0
;
font-size
:
1
2.5
px
;
font-weight
:
6
5
0
;
line-height
:
1.5
;
overflow
:
hidden
;
text-overflow
:
ellipsis
;
...
...
@@ -386,8 +422,8 @@
.task-panel-artifact-list
{
display
:
grid
;
gap
:
6
px
;
width
:
min
(
100%
,
420px
)
;
gap
:
5
px
;
width
:
100%
;
margin
:
0
;
padding
:
0
;
list-style
:
none
;
...
...
@@ -400,7 +436,7 @@
width
:
100%
;
min-width
:
0
;
align-items
:
center
;
justify-content
:
center
;
justify-content
:
flex-start
;
}
.task-panel-artifact-menu
{
...
...
@@ -409,24 +445,24 @@
width
:
100%
;
min-width
:
0
;
align-items
:
center
;
justify-content
:
center
;
justify-content
:
flex-start
;
z-index
:
4
;
}
.task-panel-artifact-trigger
{
display
:
inline-flex
;
min-height
:
3
4
px
;
min-height
:
3
2
px
;
align-items
:
center
;
justify-content
:
center
;
padding
:
0
1
4
px
;
border-radius
:
999
px
;
padding
:
0
1
2
px
;
border-radius
:
10
px
;
border
:
1px
solid
#cfe0f5
;
background
:
#ffffff
;
color
:
#1f2f49
;
box-shadow
:
0
8px
18px
rgba
(
15
,
23
,
42
,
0.06
)
;
box-shadow
:
none
;
font
:
inherit
;
font-size
:
13px
;
font-weight
:
8
00
;
font-weight
:
7
00
;
line-height
:
1
;
white-space
:
nowrap
;
cursor
:
pointer
;
...
...
@@ -445,19 +481,15 @@
}
.task-panel-artifact-popover
{
position
:
absolute
;
top
:
calc
(
100%
+
8px
);
left
:
50%
;
width
:
min
(
520px
,
calc
(
100vw
-
64px
));
max-height
:
220px
;
position
:
fixed
;
overflow-y
:
auto
;
padding
:
8
px
;
border-radius
:
1
4
px
;
padding
:
6
px
;
border-radius
:
1
2
px
;
border
:
1px
solid
rgba
(
203
,
213
,
225
,
0.96
);
background
:
#ffffff
;
box-shadow
:
0
18px
42px
rgba
(
15
,
23
,
42
,
0.14
);
transform
:
translateX
(
-50%
)
;
z-index
:
2
0
;
transform
:
none
;
z-index
:
120
0
;
}
.task-panel-artifact-popover
.task-panel-artifact-list
{
...
...
@@ -467,25 +499,32 @@
.task-panel-artifact-list
li
{
display
:
grid
;
position
:
relative
;
grid-template-columns
:
minmax
(
110px
,
0.86
fr
)
minmax
(
0
,
1.34
fr
)
;
grid-template-columns
:
minmax
(
96px
,
0.72
fr
)
minmax
(
0
,
1.28
fr
)
auto
;
align-items
:
center
;
gap
:
4
px
;
gap
:
8
px
;
min-width
:
0
;
min-height
:
34px
;
padding
:
6px
10px
;
border-radius
:
12px
;
background
:
#f8fbff
;
border
:
1px
solid
#e3ebf5
;
min-height
:
32px
;
padding
:
5px
8px
;
border-radius
:
9px
;
background
:
rgba
(
248
,
250
,
252
,
0.88
);
border
:
1px
solid
transparent
;
transition
:
border-color
160ms
ease
,
background
160ms
ease
;
}
.task-panel-artifact-list
li
:hover
,
.task-panel-artifact-list
li
:focus-within
{
border-color
:
#dbeafe
;
background
:
#ffffff
;
}
.task-panel-artifact-list
li
.task-panel-artifact-item-copied
{
padding-right
:
5
8px
;
padding-right
:
8px
;
}
.task-panel-artifact-name
,
.task-panel-artifact-url
{
min-width
:
0
;
font-size
:
1
3
px
;
font-size
:
1
2.5
px
;
line-height
:
1.5
;
overflow
:
hidden
;
text-overflow
:
ellipsis
;
...
...
@@ -494,19 +533,17 @@
.task-panel-artifact-name
{
color
:
#1f2f49
;
font-weight
:
7
0
0
;
font-weight
:
7
5
0
;
}
.task-panel-artifact-url
{
color
:
#60728c
;
justify-self
:
end
;
width
:
100%
;
min-height
:
24px
;
padding
:
0
;
border
:
0
;
background
:
transparent
;
font
:
inherit
;
text-align
:
righ
t
;
text-align
:
lef
t
;
cursor
:
pointer
;
}
...
...
@@ -524,18 +561,90 @@
}
.task-panel-artifact-copied
{
position
:
absolute
;
right
:
10px
;
top
:
50%
;
position
:
static
;
color
:
#047857
;
font-size
:
12px
;
font-weight
:
70
0
;
font-weight
:
65
0
;
line-height
:
1.5
;
text-align
:
right
;
transform
:
translateY
(
-50%
);
white-space
:
nowrap
;
}
.task-panel-loading-state
{
display
:
grid
;
gap
:
6px
;
min-width
:
860px
;
}
.task-panel-loading-row
{
display
:
grid
;
grid-template-columns
:
32px
106px
150px
138px
minmax
(
280px
,
1
fr
);
gap
:
12px
;
align-items
:
center
;
min-height
:
82px
;
padding
:
12px
14px
;
border-radius
:
12px
;
border
:
1px
solid
rgba
(
226
,
232
,
240
,
0.78
);
background
:
rgba
(
255
,
255
,
255
,
0.76
);
}
.task-panel-loading-avatar
,
.task-panel-loading-line
,
.task-panel-loading-pill
{
display
:
block
;
overflow
:
hidden
;
background
:
linear-gradient
(
90deg
,
#eef2f7
0%
,
#f8fafc
48%
,
#eef2f7
100%
);
background-size
:
220%
100%
;
animation
:
task-panel-loading-shimmer
1.3s
ease-in-out
infinite
;
}
.task-panel-loading-avatar
{
width
:
32px
;
height
:
32px
;
border-radius
:
10px
;
}
.task-panel-loading-line
{
height
:
12px
;
border-radius
:
999px
;
}
.task-panel-loading-line-name
{
width
:
88px
;
}
.task-panel-loading-line-task
{
width
:
min
(
100%
,
10em
);
}
.task-panel-loading-pill
{
width
:
78px
;
height
:
24px
;
border-radius
:
999px
;
}
.task-panel-loading-line-artifact
{
width
:
min
(
100%
,
360px
);
}
@keyframes
task-panel-greeting-caret
{
0
%,
49
%
{
opacity
:
1
;
}
50
%,
100
%
{
opacity
:
0.18
;
}
}
@keyframes
task-panel-loading-shimmer
{
0
%
{
background-position
:
120%
0
;
}
100
%
{
background-position
:
-120%
0
;
}
}
@keyframes
task-status-dot-bounce
{
0
%,
80
%,
100
%
{
opacity
:
0.42
;
...
...
@@ -554,6 +663,11 @@
}
@media
(
max-width
:
720px
)
{
.task-panel-page
{
padding
:
14px
;
border-radius
:
18px
;
}
.task-panel-header
{
align-items
:
stretch
;
flex-direction
:
column
;
...
...
@@ -562,4 +676,52 @@
.task-panel-date-field
{
width
:
fit-content
;
}
.task-panel-table
,
.task-panel-loading-state
{
min-width
:
0
;
}
.task-panel-row
{
grid-template-columns
:
minmax
(
0
,
1
fr
);
gap
:
10px
;
min-height
:
0
;
}
.task-panel-row-head
{
display
:
none
;
}
.task-panel-row
:not
(
.task-panel-row-head
)
>
div
:nth-child
(
3
)
{
padding-left
:
0
;
}
.task-panel-loading-row
{
grid-template-columns
:
32px
minmax
(
0
,
1
fr
);
}
.task-panel-loading-line-task
,
.task-panel-loading-pill
,
.task-panel-loading-line-artifact
{
grid-column
:
1
/
-1
;
}
}
@media
(
prefers-reduced-motion
:
reduce
)
{
.task-panel-greeting
::after
,
.task-panel-running-dots
span
,
.task-panel-loading-avatar
,
.task-panel-loading-line
,
.task-panel-loading-pill
{
animation
:
none
;
}
.task-panel-row
{
transition
:
none
;
}
.task-panel-row
:not
(
.task-panel-row-head
)
:hover
,
.task-panel-row
:not
(
.task-panel-row-head
)
:focus-within
{
transform
:
none
;
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a 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