Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
4fde303
feat(ui): scaffold octo ui foundation
katydids Aug 13, 2026
65988e3
feat(ui): wire octo ui integration tooling
katydids Aug 13, 2026
7e25fc0
fix(ui): address octo ui integration review
katydids Aug 13, 2026
0aa468d
feat(ui): add octo button and tag components
katydids Aug 13, 2026
ae9f7bb
fix(ui): emit valid octo ui generator export
katydids Aug 13, 2026
43eaa8b
fix(ui): cover direct web builds and css import order
katydids Aug 14, 2026
6b2e2d6
merge: sync upstream main into octo ui integration
katydids Aug 14, 2026
106afa1
merge: sync upstream main into octo ui button tag
katydids Aug 14, 2026
de17e17
Merge remote-tracking branch 'origin/codex/octo-ui-foundation-integra…
katydids Aug 14, 2026
db6fbb1
fix(ui): cover direct consumers and button sizing
katydids Aug 14, 2026
6378890
fix(ui): build octo-ui before electron dev
katydids Aug 14, 2026
158c37b
feat(ui): unify tag styles across web surfaces
Candice00711 Aug 17, 2026
8969d1c
merge: sync upstream main into tag refresh
Candice00711 Aug 17, 2026
d16036d
Merge remote-tracking branch 'upstream/main' into feat/octo-ui-tag-st…
Candice00711 Aug 17, 2026
423262e
fix(ui): resolve tag review blockers
Candice00711 Aug 17, 2026
9ab9783
fix(ui): align AI badges to xs tag size
Candice00711 Aug 17, 2026
ca10843
fix(ui): expose source runtime for development
Candice00711 Aug 17, 2026
c828047
feat(ui): add shared badge and dot components
Candice00711 Aug 18, 2026
282f175
fix(ui): address badge and dot review
Candice00711 Aug 18, 2026
ceac33c
chore: retrigger review on fresh PR
Candice00711 Aug 18, 2026
b969c7f
fix(ui): make badge and dot overrides order-safe
Candice00711 Aug 18, 2026
9c541d6
fix(ui): resolve badge and dot theme tokens locally
Candice00711 Aug 18, 2026
40445bd
feat(ui): add shared tooltip component
Candice00711 Aug 20, 2026
ecd72ef
chore: avoid stale main conflicts
Candice00711 Aug 20, 2026
4580570
fix(ui): resolve tooltip review blockers
Candice00711 Aug 20, 2026
f03f17b
fix(ui): restore tooltip suppression behavior
Candice00711 Aug 20, 2026
980d860
fix(ui): guard invalid tooltip content
Candice00711 Aug 20, 2026
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
10 changes: 10 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,16 @@ jobs:
cache: pnpm
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Octo UI tests
run: pnpm --filter @octo/ui test
- name: Badge and Dot migration tests
run: >-
pnpm --filter @octo/base exec vitest run
src/Components/ClawHealthCheckItem/ClawHealthCheckItem.test.tsx
src/Components/ConversationList/__tests__/layout.test.tsx
src/Components/ConversationList/__tests__/onlineBadge.test.tsx
src/Components/SidebarTabBar/__tests__/SidebarTabBar.test.tsx
src/ui/profileDetail/__tests__/ProfileOnlineStatus.test.tsx
- name: Agent Mail tests
run: pnpm --filter @octo/mail test
- name: Agent Mail typecheck
Expand Down
1 change: 1 addition & 0 deletions apps/extension/entrypoints/sidepanel/main.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from 'react';
import { createRoot } from 'react-dom/client';
import '@octo/base/src/theme/tokens.css';
import '@octo/ui/styles.css';
import './style.css';
import {
BaseModule,
Expand Down
8 changes: 8 additions & 0 deletions apps/extension/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,19 @@
"version": "0.0.0.1",
"type": "module",
"scripts": {
"predev": "pnpm --filter @octo/ui build",
"dev": "wxt --port 5678",
"predev:firefox": "pnpm --filter @octo/ui build",
"dev:firefox": "wxt -b firefox",
"prebuild": "pnpm --filter @octo/ui build",
"build": "wxt build",
"prebuild:firefox": "pnpm --filter @octo/ui build",
"build:firefox": "wxt build -b firefox",
"prezip": "pnpm --filter @octo/ui build",
"zip": "wxt zip",
"prezip:firefox": "pnpm --filter @octo/ui build",
"zip:firefox": "wxt zip -b firefox",
"precompile": "pnpm --filter @octo/ui build",
"compile": "tsc --noEmit",
"postinstall": "wxt prepare"
},
Expand All @@ -20,6 +27,7 @@
"@octo/contacts": "workspace:*",
"@octo/datasource": "workspace:*",
"@octo/login": "workspace:*",
"@octo/ui": "workspace:*",
"@douyinfe/semi-icons": "^2.93.0",
"@douyinfe/semi-ui": "^2.93.0",
"lucide-react": "^0.577.0",
Expand Down
5 changes: 5 additions & 0 deletions apps/web/.storybook/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,11 @@ const config: StorybookConfig = {
'@octo/base': path.resolve(__dirname, '../../../packages/dmworkbase'),
'@octo/contacts': path.resolve(__dirname, '../../../packages/dmworkcontacts'),
'@octo/login': path.resolve(__dirname, '../../../packages/dmworklogin'),
'@octo/ui/styles.css': path.resolve(
__dirname,
'../../../packages/octo-ui/src/styles/index.css',
),
'@octo/ui': path.resolve(__dirname, '../../../packages/octo-ui/src/index.ts'),
},
dedupe: ['react', 'react-dom'],
},
Expand Down
5 changes: 4 additions & 1 deletion apps/web/.storybook/preview.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import type { Preview } from '@storybook/react-vite'
import { OctoUIProvider } from '@octo/ui'
import React from 'react'

// 分层 CSS — 直接 import,不走 @import 链,避免 Vite 跨包路径问题
import '../../../packages/dmworkbase/src/theme/primitive.css'
import '../../../packages/dmworkbase/src/theme/semantic.css'
import '@octo/ui/styles.css'
import './preview.css'

const preview: Preview = {
Expand All @@ -28,7 +31,7 @@ const preview: Preview = {
} else {
document.body.removeAttribute('theme-mode')
}
return Story()
return React.createElement(OctoUIProvider, null, Story())
},
],
parameters: {
Expand Down
13 changes: 12 additions & 1 deletion apps/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,19 @@
"eject": "react-app-rewired eject",
"clean": "rimraf node_modules dist-ele build dist-ele .turbo",
"tauri": "tauri",
"prestorybook": "pnpm --filter @octo/ui build",
"storybook": "storybook dev -p 16006",
"prebuild-storybook": "pnpm --filter @octo/ui build",
"build-storybook": "storybook build",
"test:storybook": "vitest run --config vitest.storybook.config.ts"
"pretest:storybook": "pnpm --filter @octo/ui build",
"test:storybook": "vitest run --config vitest.storybook.config.ts",
"prestart": "pnpm --filter @octo/ui build",
"predev": "pnpm --filter @octo/ui build",
"predev-ele": "pnpm --filter @octo/ui build",
"prebuild": "pnpm --filter @octo/ui build",
"prebuild:electron": "pnpm --filter @octo/ui build",
"prebuild:analyzer": "pnpm --filter @octo/ui build",
"prebuild:e2e": "pnpm --filter @octo/ui build"
},
"dependencies": {
"electron-log": "^5.1.2",
Expand All @@ -76,6 +86,7 @@
"@octo/datasource": "workspace:*",
"@octo/login": "workspace:*",
"@octo/mail": "workspace:*",
"@octo/ui": "workspace:*",
"@react-pdf-viewer/core": "^3.12.0",
"@react-pdf-viewer/page-navigation": "^3.12.0",
"@react-pdf-viewer/thumbnail": "^3.12.0",
Expand Down
14 changes: 1 addition & 13 deletions apps/web/src/Components/JoinApprovalResult/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -41,18 +41,6 @@
margin: 0 0 32px;
}

/* 用更具体的选择器覆盖 Semi Button,替代 !important */
.wk-join-approval-card .wk-join-approval-btn.semi-button {
.wk-join-approval-btn {
width: 100%;
height: 44px;
font-size: 16px;
border-radius: 8px;
background-color: var(--wk-brand-primary);
border-color: var(--wk-brand-primary);
color: var(--wk-text-inverse);
}

.wk-join-approval-card .wk-join-approval-btn.semi-button:hover {
background-color: var(--wk-brand-primary-hover);
border-color: var(--wk-brand-primary-hover);
}
6 changes: 3 additions & 3 deletions apps/web/src/Components/JoinApprovalResult/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from "react";
import { Button } from "@douyinfe/semi-ui";
import { Button } from "@octo/ui";
import { useI18n, type JoinApprovalStatus } from "@octo/base";
import "./index.css";

Expand Down Expand Up @@ -34,8 +34,8 @@ export default function JoinApprovalResult({ status, onDismiss }: JoinApprovalRe
: t("app.joinApproval.submittedDesc")}
</p>
<Button
type="primary"
size="large"
variant="primary"
size="md"
className="wk-join-approval-btn"
onClick={onDismiss}
>
Expand Down
1 change: 1 addition & 0 deletions apps/web/src/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from 'react';
import { createRoot } from 'react-dom/client';
import '@octo/base/src/theme/tokens.css';
import '@octo/ui/styles.css';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
Expand Down
1 change: 1 addition & 0 deletions packages/dmworkbase/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"@dnd-kit/utilities": "^3.2.2",
"@douyinfe/semi-icons": "^2.93.0",
"@douyinfe/semi-ui": "^2.93.0",
"@octo/ui": "workspace:*",
"@emotion/react": "^11.14.0",
"@floating-ui/dom": "^1.7.6",
"@lottiefiles/lottie-player": "^1.5.5",
Expand Down
4 changes: 0 additions & 4 deletions packages/dmworkbase/src/App.css
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,3 @@ html {
overflow: hidden;
text-overflow: ellipsis;
}

body[theme-mode=dark] .semi-badge-count {
color: white;
}
28 changes: 0 additions & 28 deletions packages/dmworkbase/src/Components/AiBadge/index.css

This file was deleted.

2 changes: 2 additions & 0 deletions packages/dmworkbase/src/Components/AiBadge/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ describe("AiBadge", () => {
const html = renderToStaticMarkup(<AiBadge />);
expect(html).toContain(">AI</span>");
expect(html).toContain("ai-badge-default");
expect(html).toContain("wk-ai-tag--xs");
expect(html).not.toContain("wk-ai-tag--small");
});

it("renders a product-specific label and forwards span accessibility attributes", () => {
Expand Down
4 changes: 2 additions & 2 deletions packages/dmworkbase/src/Components/AiBadge/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from "react";
import "./index.css";
import AITag from "../../ui/AITag";

export interface AiBadgeProps extends React.HTMLAttributes<HTMLSpanElement> {
size?: "default" | "small";
Expand All @@ -11,7 +11,7 @@ const AiBadge: React.FC<AiBadgeProps> = ({ size = "default", className, children
? `ai-badge ${sizeClass} ${className}`
: `ai-badge ${sizeClass}`;

return <span className={combinedClassName} {...props}>{children}</span>;
return <AITag size="xs" className={combinedClassName} {...props}>{children}</AITag>;
};

export default AiBadge;
42 changes: 42 additions & 0 deletions packages/dmworkbase/src/Components/ChannelSetting/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -372,3 +372,45 @@
height: 100%;
overflow-y: auto;
}
.wk-channelsetting-external-group-tag {
display: inline-flex;
align-items: center;
box-sizing: border-box;
flex-shrink: 0;
height: var(--wk-sp-4);
margin-left: var(--wk-sp-1-5);
padding: 0 var(--wk-sp-1-5);
border-radius: var(--wk-r-full);
background: rgba(var(--semi-orange-5), 0.15);
color: rgba(var(--semi-orange-8), 1);
font-size: var(--wk-text-size-tiny);
font-weight: var(--wk-font-medium);
line-height: var(--wk-sp-4);
}

.wk-channelsetting-thread-status-tag {
box-sizing: border-box;
display: inline-flex;
align-items: center;
height: var(--wk-sp-5);
padding: var(--wk-sp-0-5) var(--wk-sp-2);
border-radius: var(--wk-r-full);
font-size: var(--wk-text-size-sm);
font-weight: var(--wk-font-medium);
line-height: var(--wk-sp-5);
}

.wk-channelsetting-thread-status-tag--grey {
background: rgba(var(--semi-grey-5), 0.15);
color: rgba(var(--semi-grey-8), 1);
}

.wk-channelsetting-thread-status-tag--red {
background: rgba(var(--semi-red-5), 0.15);
color: rgba(var(--semi-red-8), 1);
}

.wk-channelsetting-thread-status-tag--green {
background: rgba(var(--semi-green-5), 0.15);
color: rgba(var(--semi-green-8), 1);
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,28 +14,6 @@
min-width: 160px;
}

.hc-dot {
width: 8px;
height: 8px;
border-radius: 50%;
flex-shrink: 0;
}

/* 状态颜色:绿色 = 正常 */
.hc-dot--success {
background: var(--green, #22c55e);
}

/* 状态颜色:黄色 = 警告 */
.hc-dot--warning {
background: var(--yellow, #f59e0b);
}

/* 状态颜色:红色 = 错误 */
.hc-dot--error {
background: var(--red, #ef4444);
}

.hc-label {
font-size: 13px;
color: rgba(0, 0, 0, 0.65);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { Meta, StoryObj } from '@storybook/react';
import React from 'react';
import ClawHealthCheckItem from './ClawHealthCheckItem';

const meta = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ describe('ClawHealthCheckItem', () => {
);

const dot = screen.getByTestId('claw-health-check-item-dot');
expect(dot).toHaveClass('hc-dot--success');
expect(dot).toHaveClass('octo-ui-dot--success');
});

it('renders warning status with yellow dot', () => {
Expand All @@ -41,7 +41,7 @@ describe('ClawHealthCheckItem', () => {
);

const dot = screen.getByTestId('claw-health-check-item-dot');
expect(dot).toHaveClass('hc-dot--warning');
expect(dot).toHaveClass('octo-ui-dot--warning');
});

it('renders error status with red dot', () => {
Expand All @@ -54,7 +54,7 @@ describe('ClawHealthCheckItem', () => {
);

const dot = screen.getByTestId('claw-health-check-item-dot');
expect(dot).toHaveClass('hc-dot--error');
expect(dot).toHaveClass('octo-ui-dot--danger');
});

it('accepts custom className', () => {
Expand Down Expand Up @@ -92,12 +92,12 @@ describe('ClawHealthCheckItem', () => {
const { rerender } = render(
<ClawHealthCheckItem status="success" label="Test" value="OK" />
);
expect(screen.getByTestId('claw-health-check-item-dot')).toHaveClass('hc-dot--success');
expect(screen.getByTestId('claw-health-check-item-dot')).toHaveClass('octo-ui-dot--success');

rerender(<ClawHealthCheckItem status="warning" label="Test" value="OK" />);
expect(screen.getByTestId('claw-health-check-item-dot')).toHaveClass('hc-dot--warning');
expect(screen.getByTestId('claw-health-check-item-dot')).toHaveClass('octo-ui-dot--warning');

rerender(<ClawHealthCheckItem status="error" label="Test" value="OK" />);
expect(screen.getByTestId('claw-health-check-item-dot')).toHaveClass('hc-dot--error');
expect(screen.getByTestId('claw-health-check-item-dot')).toHaveClass('octo-ui-dot--danger');
});
});
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React from 'react';
import { Dot } from '@octo/ui';
import './ClawHealthCheckItem.css';

export type HealthStatus = 'success' | 'warning' | 'error';
Expand Down Expand Up @@ -27,13 +28,15 @@ const ClawHealthCheckItem: React.FC<ClawHealthCheckItemProps> = ({
className = '',
'data-testid': testId = 'claw-health-check-item',
}) => {
const dotTone = status === 'error' ? 'danger' : status;

return (
<div
className={`health-chip ${className}`}
data-testid={testId}
>
<span
className={`hc-dot hc-dot--${status}`}
<Dot
tone={dotTone}
data-testid={`${testId}-dot`}
/>
<span
Expand Down
Loading
Loading