Skip to content

Commit 3f2c26d

Browse files
committed
Introduce dynamic compact layout for Footer buttons using JavaScript-based footprint adjustment instead of media queries
1 parent aeb1164 commit 3f2c26d

3 files changed

Lines changed: 96 additions & 37 deletions

File tree

packages/vscode/src/views/panel/frontend/components/Layout/Footer/Footer.module.scss

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
.footer {
2+
$self: &;
23
--button-size: 24px;
34
position: relative;
45
z-index: -1; // Makes context menu of a preset appear above
@@ -53,6 +54,8 @@
5354
}
5455

5556
&__action-button {
57+
$btn: &;
58+
5659
display: flex;
5760
align-items: center;
5861
flex-shrink: 0;
@@ -72,32 +75,22 @@
7275

7376
&__text {
7477
display: inline;
78+
#{$btn}--compact & {
79+
display: none;
80+
}
7581
}
7682

7783
&__icon {
7884
display: none !important;
85+
#{$btn}--compact & {
86+
display: inline !important;
87+
}
7988
}
8089

81-
@media (max-width: 293px) {
90+
&--compact {
8291
padding: 0;
8392
width: var(--button-size);
8493
justify-content: center;
85-
86-
&__text {
87-
display: none;
88-
}
89-
90-
&__icon {
91-
display: inline !important;
92-
}
93-
}
94-
95-
&--no-shrink {
96-
@media (max-width: 293px) {
97-
padding: 0 7px;
98-
width: auto;
99-
justify-content: initial;
100-
}
10194
}
10295
}
10396
}

packages/vscode/src/views/panel/frontend/components/Layout/Footer/Footer.tsx

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import cn from 'classnames'
33
import { Icon } from '@ui/components/editor/common/Icon'
44
import styles from './Footer.module.scss'
55
import { LayoutContext } from '../../../contexts/LayoutContext'
6+
import { use_compacting } from './use-compacting'
67

78
type Props = {
89
on_donate_click: () => void
@@ -23,6 +24,8 @@ export const Footer: React.FC<Props> = ({ on_donate_click }) => {
2324
const [is_apply_disabled_temporarily, set_is_apply_disabled_temporarily] =
2425
useState(false)
2526

27+
const { container_ref, left_ref, right_ref, compact_step } = use_compacting()
28+
2629
useEffect(() => {
2730
set_is_commit_disabled_temporarily(false)
2831
}, [commit_button_enabling_trigger_count])
@@ -50,18 +53,8 @@ export const Footer: React.FC<Props> = ({ on_donate_click }) => {
5053

5154
return (
5255
<>
53-
<div className={styles.footer}>
54-
<div>
55-
<a
56-
className={cn(
57-
styles['footer__icon-button'],
58-
styles['footer__icon-button--cwc']
59-
)}
60-
href="https://codeweb.chat"
61-
title="Visit website"
62-
>
63-
<Icon variant="CODE_WEB_CHAT_LOGO" />
64-
</a>
56+
<div className={styles.footer} ref={container_ref}>
57+
<div ref={left_ref}>
6558
<a
6659
className={cn(
6760
styles['footer__icon-button'],
@@ -88,20 +81,28 @@ export const Footer: React.FC<Props> = ({ on_donate_click }) => {
8881
</a>
8982
</div>
9083

91-
<div>
84+
<div ref={right_ref}>
9285
<button
93-
className={cn(
94-
styles['footer__action-button'],
95-
styles['footer__action-button--no-shrink']
96-
)}
86+
className={cn(styles['footer__action-button'], {
87+
[styles['footer__action-button--compact']]: compact_step >= 3
88+
})}
9789
onClick={handle_apply_click}
9890
title={'Integrate copied chat response or a single code block'}
9991
disabled={is_apply_disabled_temporarily}
10092
>
101-
Apply
93+
<span className={styles['footer__action-button__text']}>Apply</span>
94+
<span
95+
className={cn(
96+
styles['footer__action-button__icon'],
97+
'codicon',
98+
'codicon-check'
99+
)}
100+
/>
102101
</button>
103102
<button
104-
className={styles['footer__action-button']}
103+
className={cn(styles['footer__action-button'], {
104+
[styles['footer__action-button--compact']]: compact_step >= 2
105+
})}
105106
onClick={on_undo_click}
106107
title={
107108
'Restore saved state of the codebase after chat/API response integration'
@@ -118,7 +119,9 @@ export const Footer: React.FC<Props> = ({ on_donate_click }) => {
118119
/>
119120
</button>
120121
<button
121-
className={styles['footer__action-button']}
122+
className={cn(styles['footer__action-button'], {
123+
[styles['footer__action-button--compact']]: compact_step >= 1
124+
})}
122125
onClick={handle_commit_click}
123126
title={
124127
has_changes_to_commit && !is_commit_disabled_temporarily
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import { useState, useLayoutEffect, useEffect, useRef } from 'react'
2+
3+
export const use_compacting = () => {
4+
const container_ref = useRef<HTMLDivElement>(null)
5+
const left_ref = useRef<HTMLDivElement>(null)
6+
const right_ref = useRef<HTMLDivElement>(null)
7+
const [compact_step, set_compact_step] = useState(0)
8+
const [thresholds, set_thresholds] = useState<{
9+
step0: number
10+
step1: number
11+
step2: number
12+
}>({ step0: 0, step1: 0, step2: 0 })
13+
14+
useLayoutEffect(() => {
15+
if (left_ref.current && right_ref.current) {
16+
const width =
17+
left_ref.current.offsetWidth + right_ref.current.offsetWidth + 6
18+
19+
if (compact_step == 0)
20+
set_thresholds((prev) => ({ ...prev, step0: width }))
21+
else if (compact_step == 1)
22+
set_thresholds((prev) => ({ ...prev, step1: width }))
23+
else if (compact_step == 2)
24+
set_thresholds((prev) => ({ ...prev, step2: width }))
25+
}
26+
}, [compact_step])
27+
28+
useEffect(() => {
29+
const observer = new ResizeObserver((entries) => {
30+
const width = entries[0].contentRect.width
31+
if (thresholds.step0 && width >= thresholds.step0) {
32+
set_compact_step(0)
33+
} else if (thresholds.step1 && width >= thresholds.step1) {
34+
set_compact_step(1)
35+
} else if (thresholds.step2 && width >= thresholds.step2) {
36+
set_compact_step(2)
37+
} else if (thresholds.step0 && width < thresholds.step0) {
38+
if (compact_step == 0) set_compact_step(1)
39+
else if (
40+
compact_step == 1 &&
41+
thresholds.step1 &&
42+
width < thresholds.step1
43+
)
44+
set_compact_step(2)
45+
else if (
46+
compact_step == 2 &&
47+
thresholds.step2 &&
48+
width < thresholds.step2
49+
)
50+
set_compact_step(3)
51+
}
52+
})
53+
if (container_ref.current) observer.observe(container_ref.current)
54+
return () => observer.disconnect()
55+
}, [thresholds, compact_step])
56+
57+
return {
58+
container_ref,
59+
left_ref,
60+
right_ref,
61+
compact_step
62+
}
63+
}

0 commit comments

Comments
 (0)