Skip to content

Commit 88eedd1

Browse files
黄桃黄桃
authored andcommitted
fix persist web clone prompt dismissal
1 parent 2faa9f5 commit 88eedd1

2 files changed

Lines changed: 60 additions & 1 deletion

File tree

apps/web/src/components/HomeView.tsx

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,14 @@ const HOME_COMPOSER_DESIGN_SYSTEM_SCOPE_KEY = 'open-design:home-composer:design-
350350
// on remount (see `pendingChipRestore` below), the same way a cross-surface
351351
// "use this plugin" hand-off resolves `pendingPluginUseHandoff`.
352352
const HOME_COMPOSER_CHIP_KEY = 'open-design:home-composer:chip';
353+
// A user can remove Website clone's automatic URL scaffold without replacing
354+
// it. Remember that opt-out independently from the active type chip: switching
355+
// to another type rewrites HOME_COMPOSER_CHIP_KEY, but must not make the
356+
// scaffold eligible to reappear after a remount/reload. The marker is scoped to
357+
// the current composer draft and is cleared with the rest of that draft after a
358+
// successful run.
359+
const HOME_COMPOSER_WEB_CLONE_SEED_DISMISSED_KEY =
360+
'open-design:home-composer:web-clone-seed-dismissed';
353361

354362
interface HomeComposerChipDraft {
355363
chipId: string | null;
@@ -448,6 +456,7 @@ function clearHomeComposerDraft(): void {
448456
writeHomeComposerDraft(HOME_COMPOSER_PROMPT_KEY, null);
449457
writeHomeComposerDraft(HOME_COMPOSER_DESIGN_SYSTEM_KEY, null);
450458
writeHomeComposerDraft(HOME_COMPOSER_DESIGN_SYSTEM_SCOPE_KEY, null);
459+
writeHomeComposerDraft(HOME_COMPOSER_WEB_CLONE_SEED_DISMISSED_KEY, null);
451460
writeHomeComposerChipDraft(null);
452461
}
453462

@@ -656,6 +665,7 @@ export function HomeView({
656665
prompt: string;
657666
designSystemId: string | null;
658667
designSystemCatalogScope: LocalCatalogScope | null;
668+
webClonePromptSeedDismissed: boolean;
659669
} | null>(null);
660670
if (restoredDraftRef.current === null) {
661671
restoredDraftRef.current = {
@@ -664,6 +674,8 @@ export function HomeView({
664674
designSystemCatalogScope: readLocalCatalogScopeDraft(
665675
HOME_COMPOSER_DESIGN_SYSTEM_SCOPE_KEY,
666676
),
677+
webClonePromptSeedDismissed:
678+
readHomeComposerDraft(HOME_COMPOSER_WEB_CLONE_SEED_DISMISSED_KEY) === '1',
667679
};
668680
}
669681
const restoredDraft = restoredDraftRef.current;
@@ -712,6 +724,9 @@ export function HomeView({
712724
const [mcpServers, setMcpServers] = useState<McpServerConfig[]>([]);
713725
const [mcpLoading, setMcpLoading] = useState(true);
714726
const [prompt, setPrompt] = useState(() => restoredPrompt);
727+
const webClonePromptSeedDismissedRef = useRef(
728+
restoredDraft.webClonePromptSeedDismissed,
729+
);
715730
// Treat a restored non-empty prompt as user-edited so the plugin/skill
716731
// replacement guard still asks before clobbering it. The Website-clone
717732
// scaffold is mode UI, not a user draft; the exact-text fallback migrates
@@ -2081,6 +2096,19 @@ export function HomeView({
20812096
}
20822097

20832098
function handlePromptChange(nextPrompt: string) {
2099+
// This handler only runs for real editor changes. If the user empties a
2100+
// Website-clone draft, treat that as an explicit dismissal of the automatic
2101+
// URL scaffold and persist it across tab switches, remounts, and reloads.
2102+
// Programmatic cleanup uses setPrompt directly and therefore cannot set the
2103+
// dismissal marker accidentally.
2104+
if (
2105+
active?.chipId === 'web-clone'
2106+
&& prompt.trim().length > 0
2107+
&& nextPrompt.trim().length === 0
2108+
) {
2109+
webClonePromptSeedDismissedRef.current = true;
2110+
writeHomeComposerDraft(HOME_COMPOSER_WEB_CLONE_SEED_DISMISSED_KEY, '1');
2111+
}
20842112
setPrompt(nextPrompt);
20852113
setPromptEditedByUser(true);
20862114
if (active?.promptSeedKind) {
@@ -2566,7 +2594,9 @@ export function HomeView({
25662594
// gets the localized "clone this site: <url>" scaffold instead of
25672595
// staying blank. A non-empty draft is the user's — leave it alone.
25682596
const promptSeed =
2569-
chip.id === 'web-clone' && prompt.trim().length === 0
2597+
chip.id === 'web-clone'
2598+
&& prompt.trim().length === 0
2599+
&& !webClonePromptSeedDismissedRef.current
25702600
? t('homeHero.chip.webClonePromptSeed')
25712601
: null;
25722602
if (chip.group === 'create') {

apps/web/tests/components/HomeView.web-clone-tracking.test.tsx

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,35 @@ describe('web-clone example-card tracking', () => {
195195
});
196196
});
197197

198+
it('keeps a manually dismissed Website-clone scaffold empty across a remount', async () => {
199+
writeHomeGuideStage('done');
200+
stubPlugins();
201+
const firstMount = renderHome('zh-CN');
202+
203+
await pickHomeTemplate('web-clone');
204+
await waitFor(() => {
205+
expect(homeHeroPromptText()).toBe('想要复刻的网站链接:');
206+
});
207+
208+
setHomeHeroPrompt('');
209+
await waitFor(() => {
210+
expect(screen.getByTestId('home-hero-input').textContent).toBe('');
211+
});
212+
213+
await pickHomeTemplate('prototype');
214+
await waitFor(() => {
215+
expect(screen.getByTestId('home-hero-input').textContent).toBe('');
216+
});
217+
218+
firstMount.unmount();
219+
renderHome('zh-CN');
220+
await pickHomeTemplate('web-clone');
221+
222+
await waitFor(() => {
223+
expect(screen.getByTestId('home-hero-input').textContent).toBe('');
224+
});
225+
});
226+
198227
it('cleans up a Website-clone scaffold leaked into another persisted type by the old behavior', async () => {
199228
writeHomeGuideStage('done');
200229
stubPlugins();

0 commit comments

Comments
 (0)