Skip to content
Merged
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
14 changes: 13 additions & 1 deletion packages/components/src/icon/iconfont/iconfont.css
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,19 @@
url('iconfont.svg?t=1667290291241#kaitian-icon') format('svg');
}

.kaitian-icon[class*='kticon-'] {
font: normal normal normal 16px/1 "kaitian-icon";
display: block;
text-decoration: none;
text-rendering: auto;
text-align: center;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
}

.kaitian-icon {
font-family: "kaitian-icon" !important;
font-size: 16px;
Expand Down Expand Up @@ -719,4 +732,3 @@
.kticon-folder-fill:before {
content: "\e85e";
}

5 changes: 4 additions & 1 deletion packages/components/src/popover/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ export enum PopoverPosition {

function noop() {}

// style 里设置的是 7, 但是在 top 模式下会有一部分与元素遮挡
const arrowSizeWrap = 8;

export const Popover: React.FC<{
id: string;
insertClass?: string;
Expand Down Expand Up @@ -87,7 +90,7 @@ export const Popover: React.FC<{
contentRect.right - window.innerWidth > 0
? window.innerWidth - contentRect.width
: left - contentRect.width / 2 + width / 2;
const contentTop = top - contentRect.height - 7;
const contentTop = top - contentRect.height - arrowSizeWrap;
contentEl.current.style.left = (contentLeft < 0 ? 0 : contentLeft) + 'px';
contentEl.current.style.top = (contentTop < 0 ? 0 : contentTop) + 'px';
contentEl.current.style.visibility = 'visible';
Expand Down
34 changes: 34 additions & 0 deletions packages/core-browser/__tests__/utils/parse.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { LabelIcon, parseLabel } from '../../src/utils/parse';

describe('it can parse', () => {
it('can parse label with icon', () => {
const labels = parseLabel('$(hello) world');
expect(labels).toHaveLength(2);
expect((labels[0] as LabelIcon).name).toEqual('hello');
});
it('can parse label with multiple icon', () => {
const labels = parseLabel('$(hello) world $(qwq)');
expect(labels).toHaveLength(3);
expect((labels[0] as LabelIcon).name).toEqual('hello');
expect((labels[2] as LabelIcon).name).toEqual('qwq');
});

it('can parse label with icon animation', () => {
const labels = parseLabel('$(hello~spin) world $(qwq)');
expect(labels).toHaveLength(3);
expect((labels[0] as LabelIcon).name).toEqual('hello');
expect((labels[0] as LabelIcon).owner).toBeUndefined();
expect((labels[0] as LabelIcon).animation).toEqual('spin');
expect((labels[2] as LabelIcon).name).toEqual('qwq');
expect((labels[2] as LabelIcon).owner).toBeUndefined();
});
it('can parse label with icon owner', () => {
const labels = parseLabel('$(kt/hello~spin) world $(qwq)');
expect(labels).toHaveLength(3);
expect((labels[0] as LabelIcon).name).toEqual('hello');
expect((labels[0] as LabelIcon).animation).toEqual('spin');
expect((labels[0] as LabelIcon).owner).toEqual('kt');
expect((labels[2] as LabelIcon).name).toEqual('qwq');
expect((labels[2] as LabelIcon).owner).toBeUndefined();
});
});
4 changes: 4 additions & 0 deletions packages/core-browser/src/style/icon/icon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export function getOctIcon(iconKey: string) {
}

export const CODICON_OWNER = 'codicon';
export const KTICON_OWNER = 'kticon';

const codIconId = [
'add',
Expand Down Expand Up @@ -502,6 +503,9 @@ export function getExternalIcon(iconKey: string, iconOwner = CODICON_OWNER, fall
if (fallback && iconOwner === CODICON_OWNER && !codIconId.includes(iconKey)) {
return getOctIcon(iconKey);
}
if (iconOwner === KTICON_OWNER) {
return `kaitian-icon ${iconOwner}-${iconKey}`;
}
return `${iconOwner} ${iconOwner}-${iconKey}`;
}

Expand Down
13 changes: 13 additions & 0 deletions packages/core-browser/src/style/icon/index.less
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,19 @@
margin-right: 0;
}

.kaitian-icon[class*='kticon-'] {
font: normal normal normal 16px/1 'kaitian-icon';
display: block;
text-decoration: none;
text-rendering: auto;
text-align: center;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
}

.kaitian-icon {
&::before {
font-family: 'kaitian-icon' !important;
Expand Down
12 changes: 11 additions & 1 deletion packages/core-browser/src/utils/parse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

export interface LabelIcon {
name: string;
owner?: string;
animation?: string;
}

Expand Down Expand Up @@ -52,10 +53,19 @@ export function parseLabel(text: string): LabelPart[] {
} else {
if (char === ')') {
const iconClassArr = potentialIcon.substring(2, potentialIcon.length).split('~');
let name = iconClassArr[0];
let owner: string | undefined;
if (name) {
const index = name.indexOf('/');
if (index !== -1) {
owner = name.substring(0, index);
name = name.substring(index + 1);
}
}
if (parserArray[arrPointer] !== '') {
arrPointer++;
}
parserArray[arrPointer] = { name: iconClassArr[0], animation: iconClassArr[1] };
parserArray[arrPointer] = { name, owner, animation: iconClassArr[1] };
arrPointer++;
potentialIcon = '';
} else {
Expand Down
1 change: 1 addition & 0 deletions packages/i18n/src/common/en-US.lang.ts
Original file line number Diff line number Diff line change
Expand Up @@ -845,6 +845,7 @@ export const localizationBundle = {
'markers.filter.placeholder': 'Filter. E.g.: text, **/*.ts, !**/node_modules/**',
'markers.filter.content.empty': 'No results found with provided filter criteria.',
'markers.filter.reset': 'Clear Filter.',
'markers.status.no.problems': 'No Problems',

'app.quit': 'Quit',
'view.zoomReset': 'Zoom Reset',
Expand Down
1 change: 1 addition & 0 deletions packages/i18n/src/common/zh-CN.lang.ts
Original file line number Diff line number Diff line change
Expand Up @@ -820,6 +820,7 @@ export const localizationBundle = {
'markers.filter.placeholder': '筛选器,例如:text、**/*.ts、!**/node_modules/**',
'markers.filter.content.empty': '在给定的筛选条件下,没有找到结果。',
'markers.filter.reset': '清除筛选器',
'markers.status.no.problems': '没有问题',

'output.channel.clear': '清除输出面板的内容',

Expand Down
86 changes: 77 additions & 9 deletions packages/markers/src/browser/markers-contribution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,13 @@ import {
CommandRegistry,
ComponentContribution,
ComponentRegistry,
Disposable,
Domain,
IStatusBarService,
localize,
Logger,
MARKER_COMMANDS,
StatusBarAlignment,
} from '@opensumi/ide-core-browser';
import { IMainLayoutService, MainLayoutContribution } from '@opensumi/ide-main-layout';

Expand All @@ -17,8 +21,20 @@ import { MarkerService } from './markers-service';
import { MarkerPanel } from './markers-tree.view';
import Messages from './messages';

function normalize(num: number) {
const limit = 100;
const msg = `${limit - 1}+`;
if (num >= limit) {
return msg;
}
return num.toString();
}

@Domain(CommandContribution, ComponentContribution, MainLayoutContribution)
export class MarkersContribution implements CommandContribution, ComponentContribution, MainLayoutContribution {
export class MarkersContribution
extends Disposable
implements CommandContribution, ComponentContribution, MainLayoutContribution
{
@Autowired()
logger: Logger;

Expand All @@ -27,14 +43,58 @@ export class MarkersContribution implements CommandContribution, ComponentContri

@Autowired(IMarkerService)
protected readonly markerService: MarkerService;
@Autowired(IStatusBarService)
private readonly statusBar: IStatusBarService;

onDidRender() {
const handler = this.mainlayoutService.getTabbarHandler(MARKER_CONTAINER_ID);
if (handler) {
this.addDispose(
this.markerService.getManager().onMarkerChanged(() => {
const badge = this.markerService.getBadge();
handler.setBadge(badge || '');
}),
);
}
this.updateStatusBar();
this.addDispose(
this.markerService.getManager().onMarkerChanged(() => {
const badge = this.markerService.getBadge();
handler.setBadge(badge || '');
this.updateStatusBar();
}),
);
}

statusBarId = 'markers-status';
updateStatusBar() {
const markerManager = this.markerService.getManager();
const stats = markerManager.getStats();
if (stats) {
const tooltipString = [] as string[];
if (stats.errors > 0) {
tooltipString.push(`Errors(${stats.errors})`);
}
if (stats.warnings > 0) {
tooltipString.push(`Warnings(${stats.warnings})`);
}
if (stats.infos > 0) {
tooltipString.push(`Infos(${stats.infos})`);
}
this.statusBar.addElement(this.statusBarId, {
name: localize('status-bar.editor-langStatus'),
alignment: StatusBarAlignment.LEFT,
text: [
`$(kticon/close-circle) ${normalize(stats.errors)}`,
`$(kticon/error) ${normalize(stats.warnings)}`,
`$(kticon/info-circle) ${normalize(stats.infos)}`,
].join(' '),
priority: 1,
tooltip: tooltipString.length > 0 ? tooltipString.join(', ') : localize('markers.status.no.problems'),
onClick: () => {
this.toggleMarkerTabbar();
},
});
} else {
this.statusBar.removeElement(this.statusBarId);
}
}

Expand All @@ -55,13 +115,24 @@ export class MarkersContribution implements CommandContribution, ComponentContri
);
}

showMarkerTabbar() {
const tabbarHandler = this.mainlayoutService.getTabbarHandler(MARKER_CONTAINER_ID);
tabbarHandler?.activate();
}

toggleMarkerTabbar() {
const tabbarHandler = this.mainlayoutService.getTabbarHandler(MARKER_CONTAINER_ID);
if (tabbarHandler) {
tabbarHandler.isActivated() ? tabbarHandler.deactivate() : tabbarHandler.activate();
}
}

registerCommands(commands: CommandRegistry): void {
commands.registerCommand(
{ id: MARKER_COMMANDS.SHOW_ERRORS_WARNINGS.id },
{
execute: () => {
const tabbarHandler = this.mainlayoutService.getTabbarHandler(MARKER_CONTAINER_ID);
tabbarHandler?.activate();
this.showMarkerTabbar();
},
},
);
Expand All @@ -70,10 +141,7 @@ export class MarkersContribution implements CommandContribution, ComponentContri
{ id: MARKER_COMMANDS.TOGGLE_SHOW_ERRORS_WARNINGS.id },
{
execute: () => {
const tabbarHandler = this.mainlayoutService.getTabbarHandler(MARKER_CONTAINER_ID);
if (tabbarHandler) {
tabbarHandler.isActivated() ? tabbarHandler.deactivate() : tabbarHandler.activate();
}
this.toggleMarkerTabbar();
},
},
);
Expand Down
9 changes: 2 additions & 7 deletions packages/status-bar/src/browser/status-bar-item.view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -127,20 +127,15 @@ export const StatusBarItem = React.memo((props: StatusBarEntry) => {
key={key}
className={cls(
styles.icon,
getExternalIcon(item.name),
getExternalIcon(item.name, item.owner),
`${item.animation ? 'iconfont-anim-' + item.animation : ''}`,
)}
></span>
);
} else {
// 22px高度限制用于解决文本超长时文本折叠问题
return (
<span
style={{ marginLeft: iconClass || hasIcon ? '2px' : 0, height: '22px', lineHeight: '22px' }}
key={key}
aria-label={ariaLabel}
role={role}
>
<span style={{ height: '22px', lineHeight: '22px' }} key={key} aria-label={ariaLabel} role={role}>
{replaceLocalizePlaceholder(item)}
</span>
);
Expand Down
31 changes: 9 additions & 22 deletions packages/status-bar/src/browser/status-bar.module.less
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,6 @@
padding-right: calc(@base-ui-spacing*2);
}

.element {
color: var(--statusBar-foreground);
display: flex;
align-items: center;
padding: 0 4px;
font-size: @statusBar-font-size;
&:first-child {
padding: 0px 10px;
}
}

.element.hasCommand:hover {
background-color: var(--statusBarItem-hoverBackground);
cursor: pointer;
Expand All @@ -55,22 +44,20 @@
margin-left: @base-ui-spacing;
}

// .element {
// /* https://css-tricks.com/os-specific-fonts-css/#article-header-id-0 */
// /* https://github.com/Microsoft/vscode/blob/5dbdc8d19c8cf6dd10d558eabcc48bba962ea45f/src/vs/workbench/browser/media/style.css#L8-L24 */
// font-family: -apple-system, BlinkMacSystemFont, "Segoe WPC", "Segoe UI", "Ubuntu", "Droid Sans", sans-serif;
// font-size: 12px;
// text-rendering: auto;
// text-decoration: none;
// -webkit-font-smoothing: antialiased;
// -moz-osx-font-smoothing: grayscale;
// }

.element {
color: var(--statusBar-foreground);
display: flex;
align-items: center;
padding: 0 2px;
font-size: @statusBar-font-size;
&:first-child {
padding: 0px 10px;
}
span.icon {
display: flex;
align-items: center;
font-size: 1em;
margin: 0 2px;

&::before {
vertical-align: middle;
Expand Down