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
5 changes: 5 additions & 0 deletions .changeset/many-pandas-breathe.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@lynx-js/a2ui-reactlynx": patch
---

refactor theme styles
Comment thread
HuJean marked this conversation as resolved.
2 changes: 1 addition & 1 deletion packages/genui/a2ui-playground/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ Web build has two entrypoints (see `rsbuild.config.ts`):
reload when the init data changes.

The control panel builds a `/render.html?...` URL with base64-encoded payload
(`src/utils/renderUrl.ts`) and embeds it in an `<iframe>` (see `MobilePreview`).
(`src/utils/renderUrl.ts`) and embeds it in an `<iframe>`(see `PreviewViewport.tsx`).

## Lynx App Architecture (What Runs Inside <lynx-view>)

Expand Down
20 changes: 7 additions & 13 deletions packages/genui/a2ui-playground/lynx-src/a2ui/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,8 @@ function normalizeInitDataLike(raw: unknown): InitData {
const theme = obj.theme;
if (theme === 'light' || theme === 'dark') {
out.theme = theme;
} else if (theme === 'Dark' || theme === 'Light') {
out.theme = theme.toLowerCase() as Theme;
}

return out;
Expand Down Expand Up @@ -340,8 +342,9 @@ export function App() {
[streamConfig.theme],
);
const themeClassName = theme === 'dark'
? 'luna-dark a2ui-dark'
: 'luna-light a2ui-light';
? 'luna-dark'
: 'luna-light';
const surfaceThemeClassName = theme === 'dark' ? ' a2ui-dark' : ' a2ui-light';
const isPlaybackPaused = useMemo(
() => effectiveData.playbackPaused === true,
[effectiveData.playbackPaused],
Expand Down Expand Up @@ -485,16 +488,7 @@ export function App() {
</view>
)
: (
<view
style={{
flex: 1,
minHeight: 0,
position: 'relative',
display: 'flex',
flexDirection: 'column',
gap: '12px',
}}
>
<view className='a2ui-root-container'>
{!isInstantPreview && store === null && error === ''
? (
<view className='a2ui-loadingOverlay'>
Expand All @@ -518,7 +512,7 @@ export function App() {
void agentRef.current?.onAction(action);
}}
wrapSurface={(c) => (
<view className={themeClassName}>{c}</view>
<view className={surfaceThemeClassName}>{c}</view>
)}
renderFallback={() => (
<view style={{ padding: '12px' }}>
Expand Down
89 changes: 59 additions & 30 deletions packages/genui/a2ui-playground/lynx-src/a2ui/index.css

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion packages/genui/a2ui-playground/lynx.config.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright 2026 The Lynx Authors. All rights reserved.
// Licensed under the Apache License Version 2.0 that can be found in the
// LICENSE file in the root directory of this source tree.

import { pluginLynxConfig } from '@lynx-js/config-rsbuild-plugin';
import { pluginQRCode } from '@lynx-js/qrcode-rsbuild-plugin';
import { pluginReactLynx } from '@lynx-js/react-rsbuild-plugin';
import { defineConfig } from '@lynx-js/rspeedy';
Expand All @@ -18,6 +18,9 @@ export default defineConfig({
pluginReactLynx({
defaultDisplayLinear: false,
}),
pluginLynxConfig({
enableCSSInlineVariables: true,
}),
],
source: {
entry: {
Expand Down
1 change: 1 addition & 0 deletions packages/genui/a2ui-playground/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"react-dom": "19.2.4"
},
"devDependencies": {
"@lynx-js/config-rsbuild-plugin": "workspace:*",
"@lynx-js/qrcode-rsbuild-plugin": "workspace:*",
"@lynx-js/react-rsbuild-plugin": "workspace:*",
"@lynx-js/rspeedy": "workspace:*",
Expand Down
33 changes: 0 additions & 33 deletions packages/genui/a2ui-playground/src/components/MobilePreview.tsx

This file was deleted.

46 changes: 29 additions & 17 deletions packages/genui/a2ui-playground/src/pages/DemosPage.css
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,10 @@
text-transform: uppercase;
}

[data-theme="dark"] .exampleCardBadge {
background: transparent;
}

.detailSidebar {
width: 280px;
}
Expand All @@ -205,22 +209,20 @@
gap: 8px;
min-height: 34px;
padding: 8px 14px;
border: 1px solid rgba(0, 0, 0, 0.08);
border: 1px solid var(--geist-border);
border-radius: 999px;
background:
linear-gradient(
180deg,
rgba(255, 255, 255, 0.82),
rgba(255, 255, 255, 0.64)
),
var(--geist-surface);
background: color-mix(
in srgb,
var(--geist-background) 82%,
var(--geist-surface)
);
color: var(--geist-foreground);
font-size: 13px;
font-weight: 600;
line-height: 1;
letter-spacing: 0.01em;
cursor: pointer;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
box-shadow: var(--geist-shadow-sm);
transition:
background var(--geist-transition),
border-color var(--geist-transition),
Expand All @@ -230,15 +232,25 @@

.detailBackButton:hover {
border-color: var(--geist-border-hover);
background:
linear-gradient(
180deg,
rgba(255, 255, 255, 0.96),
rgba(255, 255, 255, 0.78)
),
var(--geist-background);
background: var(--geist-background);
transform: translateY(-1px);
box-shadow: 0 8px 18px rgba(0, 0, 0, 0.08);
box-shadow: var(--geist-shadow-md);
}

html[data-theme="dark"] .detailBackButton {
background: color-mix(
in srgb,
var(--geist-background) 72%,
var(--geist-surface)
);
}

html[data-theme="dark"] .detailBackButton:hover {
background: color-mix(
in srgb,
var(--geist-background) 60%,
var(--geist-surface)
);
}

.detailBackIcon {
Expand Down
15 changes: 8 additions & 7 deletions packages/genui/a2ui-playground/src/pages/PlaybackPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { useResizablePanels } from '../hooks/useResizablePanels.js';
import { DEFAULT_A2UI_DEMO_URL } from '../utils/demoUrl.js';
import type { Protocol } from '../utils/protocol.js';

type Theme = 'light' | 'dark';
type PlayState = 'idle' | 'playing' | 'paused' | 'done';
type PlaybackControlAction = 'pause' | 'resume';
type PlaybackProgressStatus = 'idle' | 'streaming' | 'paused' | 'done';
Expand All @@ -31,8 +32,8 @@ function formatChunk(msg: unknown): string {
return JSON.stringify(msg, null, 2);
}

export function PlaybackPage(props: { protocol: Protocol }) {
const { protocol } = props;
export function PlaybackPage(props: { protocol: Protocol; theme: Theme }) {
const { protocol, theme } = props;

const [scenarioId, setScenarioId] = useState<string>(
ALL_SCENARIOS[0]?.id ?? '',
Expand All @@ -41,9 +42,7 @@ export function PlaybackPage(props: { protocol: Protocol }) {
const [speed, setSpeed] = useState(1);
const [iframeKey, setIframeKey] = useState(0);
const [deliveredCount, setDeliveredCount] = useState(0);
const streamTimerRef = useRef<ReturnType<typeof window.setTimeout> | null>(
null,
);
const streamTimerRef = useRef<number | null>(null);

const iframeRef = useRef<HTMLIFrameElement | null>(null);
const pendingSendRef = useRef<{ msgs: unknown[]; speed: number } | null>(
Expand Down Expand Up @@ -78,8 +77,9 @@ export function PlaybackPage(props: { protocol: Protocol }) {
const url = new URL('render.html', base);
url.searchParams.set('protocol', protocol.name);
url.searchParams.set('demoUrl', DEFAULT_A2UI_DEMO_URL);
url.searchParams.set('theme', theme);
return url.toString();
}, [protocol.name]);
}, [protocol.name, theme]);

const sendToIframe = useCallback((
msgs: unknown[],
Expand All @@ -94,11 +94,12 @@ export function PlaybackPage(props: { protocol: Protocol }) {
messages: msgs,
speed: spd,
playbackMode: true,
theme,
},
},
'*',
);
}, []);
}, [theme]);

const sendPlaybackControlToIframe = useCallback(
(action: PlaybackControlAction) => {
Expand Down
Loading
Loading