style(vscode-ide-companion/ui): improve component styling and layout

This commit is contained in:
yiliang114
2025-12-05 18:03:37 +08:00
parent 13aa4b03c7
commit ac9cb3a6d3
6 changed files with 47 additions and 30 deletions

View File

@@ -20,7 +20,7 @@ export const InterruptedMessage: React.FC<InterruptedMessageProps> = ({
style={{
width: '100%',
alignItems: 'flex-start',
paddingLeft: '30px', // keep alignment with other assistant messages, but no status icon
paddingLeft: '10px', // keep alignment with other assistant messages, but no status icon
position: 'relative',
paddingTop: '8px',
paddingBottom: '8px',

View File

@@ -42,7 +42,8 @@ const parseTodoEntries = (textOutputs: string[]): TodoEntry[] => {
const lines = text.split(/\r?\n/);
const entries: TodoEntry[] = [];
const todoRe = /^(?:\s*(?:[-*]|\d+[.)])\s*)?\[( |x|X|-)\]\s+(.*)$/;
// Accept [ ], [x]/[X] and in-progress markers [-] or [*]
const todoRe = /^(?:\s*(?:[-*]|\d+[.)])\s*)?\[( |x|X|-|\*)\]\s+(.*)$/;
for (const line of lines) {
const m = line.match(todoRe);
if (m) {
@@ -51,7 +52,7 @@ const parseTodoEntries = (textOutputs: string[]): TodoEntry[] => {
const status: EntryStatus =
mark === 'x' || mark === 'X'
? 'completed'
: mark === '-'
: mark === '-' || mark === '*'
? 'in_progress'
: 'pending';
if (title) {

View File

@@ -42,7 +42,8 @@ const parsePlanEntries = (textOutputs: string[]): PlanEntry[] => {
const lines = text.split(/\r?\n/);
const entries: PlanEntry[] = [];
const todoRe = /^(?:\s*(?:[-*]|\d+[.)])\s*)?\[( |x|X|-)\]\s+(.*)$/;
// Accept [ ], [x]/[X] and in-progress markers [-] or [*]
const todoRe = /^(?:\s*(?:[-*]|\d+[.)])\s*)?\[( |x|X|-|\*)\]\s+(.*)$/;
for (const line of lines) {
const m = line.match(todoRe);
if (m) {
@@ -51,7 +52,7 @@ const parsePlanEntries = (textOutputs: string[]): PlanEntry[] => {
const status: EntryStatus =
mark === 'x' || mark === 'X'
? 'completed'
: mark === '-'
: mark === '-' || mark === '*'
? 'in_progress'
: 'pending';
if (title) {

View File

@@ -33,7 +33,7 @@ export const CheckboxDisplay: React.FC<CheckboxDisplayProps> = ({
// Pseudo-elements do not reliably render on <input> in Chromium (VS Code webviews),
// which caused the missing icon. This version is font-free and uses borders.
const showCheck = !!checked && !indeterminate;
const showDash = !!indeterminate;
const showInProgress = !!indeterminate;
return (
<span
@@ -66,16 +66,18 @@ export const CheckboxDisplay: React.FC<CheckboxDisplayProps> = ({
].join(' ')}
/>
) : null}
{showDash ? (
{showInProgress ? (
<span
aria-hidden
className={[
'absolute block',
'absolute inline-block',
'left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2',
'w-2 h-[2px] rounded-sm',
'bg-[#e1c08d]',
// Use a literal star; no icon font needed
'text-[11px] leading-none text-[#e1c08d] select-none',
].join(' ')}
/>
>
*
</span>
) : null}
</span>
);

View File

@@ -11,7 +11,7 @@
=========================== */
:root {
/* Qwen Brand Colors */
--app-qwen-orange: #615fff;
--app-qwen-theme: #615fff;
--app-qwen-clay-button-orange: #4f46e5;
--app-qwen-ivory: #f5f5ff;
--app-qwen-slate: #141420;
@@ -46,7 +46,7 @@
--app-input-placeholder-foreground: var(--vscode-input-placeholderForeground);
--app-input-secondary-background: var(--vscode-menu-background);
/* Input Highlight (focus ring/border) */
--app-input-highlight: var(--app-qwen-orange);
--app-input-highlight: var(--app-qwen-theme);
/* Code Highlighting */
--app-code-background: var(--vscode-textCodeBlock-background, rgba(0, 0, 0, 0.05));
@@ -211,7 +211,7 @@ button {
}
.input-field:focus {
border-color: var(--app-qwen-orange);
border-color: var(--app-qwen-theme);
}
.input-field:disabled {
@@ -355,7 +355,7 @@ button {
=========================== */
.permission-request-card {
background: var(--app-input-background);
border: 1px solid var(--app-qwen-orange);
border: 1px solid var(--app-qwen-theme);
border-radius: var(--corner-radius-medium);
margin: var(--app-spacing-medium) 0;
margin-bottom: var(--app-spacing-xlarge);
@@ -500,18 +500,10 @@ button {
}
.permission-option.selected {
border-color: var(--app-qwen-orange);
border-color: var(--app-qwen-theme);
background: rgba(97, 95, 255, 0.1);
}
.permission-option.allow {
/* Allow options */
}
.permission-option.reject {
/* Reject options */
}
.permission-radio {
flex-shrink: 0;
}
@@ -540,7 +532,7 @@ button {
.permission-option.selected .permission-option-number {
color: var(--app-qwen-ivory);
background-color: var(--app-qwen-orange);
background-color: var(--app-qwen-theme);
}
.permission-always-badge {

View File

@@ -51,7 +51,8 @@
.composer-form:focus-within {
/* match existing highlight behavior */
border-color: var(--app-input-highlight);
box-shadow: 0 1px 2px color-mix(in srgb, var(--app-input-highlight), transparent 80%);
box-shadow: 0 1px 2px
color-mix(in srgb, var(--app-input-highlight), transparent 80%);
}
/* Composer: input editable area */
@@ -62,7 +63,11 @@
font-size: var(--vscode-chat-font-size, 13px);
color: var(--app-input-foreground);
}
.composer-input:empty:before {
/* Show placeholder when truly empty OR when flagged as empty via data attribute.
The data attribute is needed because some browsers insert a <br> in
contentEditable, which breaks :empty matching. */
.composer-input:empty:before,
.composer-input[data-empty='true']::before {
content: attr(data-placeholder);
color: var(--app-input-placeholder-foreground);
pointer-events: none;
@@ -76,7 +81,7 @@
outline: none;
}
.composer-input:disabled,
.composer-input[contenteditable="false"] {
.composer-input[contenteditable='false'] {
color: #999;
cursor: not-allowed;
}
@@ -105,7 +110,8 @@
filter: brightness(1.1);
}
.btn-text-compact > svg {
height: 1em; /* match font size */
height: 1em;
width: 1em;
flex-shrink: 0;
}
.btn-text-compact > span {
@@ -119,7 +125,9 @@
}
@media screen and (max-width: 300px) {
.btn-text-compact > svg { display: none; }
.btn-text-compact > svg {
display: none;
}
}
/* Icon-only button, compact square (26x26) */
@@ -173,3 +181,16 @@
overflow-wrap: anywhere;
}
}
/* ===========================
Utilities
=========================== */
@layer utilities {
/* Multi-line clamp with ellipsis (Chromium-based webview supported) */
.q-line-clamp-3 {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
overflow: hidden;
}
}