diff --git a/.sync/log/7bdcb1381c7cb55c7fd602545b3ddc4461b19c43.md b/.sync/log/7bdcb1381c7cb55c7fd602545b3ddc4461b19c43.md new file mode 100644 index 000000000..e20d74904 --- /dev/null +++ b/.sync/log/7bdcb1381c7cb55c7fd602545b3ddc4461b19c43.md @@ -0,0 +1,39 @@ +# Port: feat(Prompt): add `claude` action (#6693) + +**Upstream:** `7bdcb1381c7cb55c7fd602545b3ddc4461b19c43` (nuxt/ui) +**Decision:** port + +## Upstream change +`prose/Prompt.vue` gains a `claude` action alongside `copy`/`cursor`/`windsurf`: +the `copy` button is now **always** shown (default `actions` → `[]`, and a new +`actions` computed forces `copy` in via `[...new Set(['copy', ...props.actions])]`); +adds `openInClaude()` (`claude://code/new?q=`); the `openIn*` helpers are +condensed to one-liners with `encodeURIComponent`; template `v-if`s switch from +`props.actions` to the `actions` computed and a Claude `UButton` is added. Docs +`prompt.md` updated (copy always displayed; example uses `cursor`+`claude`). + +## b24ui port — adapted (icon divergence) +b24ui's `prose/Prompt.vue` matched upstream (with b24ui naming: `b24ui`, +`B24Button`, `appConfig.b24ui`, `icons` from `dictionary/icons`). Applied the +type (`+'claude'` + jsdoc), the `actions: () => []` default, the `actions` +computed, the `openIn*` refactor + `openInClaude`, and the template +`actions.includes(...)` switch + the Claude `B24Button`. + +### Deviation — inline `ClaudeIcon` +Upstream uses `icon="i-simple-icons-claude"` (iconify). b24ui has no +`@nuxt/icon`/iconify and no Claude brand icon in `@bitrix24/b24icons-vue`, so — +mirroring the existing hand-rolled `CursorIcon`/`WindsurfIcon` inline-SVG +`IconComponent`s in `dictionary/icons.ts` — added a `ClaudeIcon` inline SVG using +the **simple-icons `claude`** path (fetched verbatim from the simple-icons +package), registered in the icons dictionary. The Claude button uses +`:icon="icons.ClaudeIcon"` + `color="air-secondary-accent-2"` (matching +Cursor/Windsurf). + +## Tests +No upstream Prompt spec change. 14 snapshots updated (`ProsePrompt` × nuxt/vue): +benign — existing cases gain the Claude button's `` placeholder (it's +inactive unless `claude` is requested), and the copy button now always renders +via the `actions` computed. Suite 5289 passed. + +## Verify (CI=true) +`dev:prepare` · `lint` · `typecheck` · `test` · `build` — all green. diff --git a/.sync/nuxt-ui.json b/.sync/nuxt-ui.json index c97a35f62..897dd364c 100644 --- a/.sync/nuxt-ui.json +++ b/.sync/nuxt-ui.json @@ -2,7 +2,7 @@ "upstream": "nuxt/ui", "branch": "v4", "sync_enabled": false, - "cursor": "d0581cf88fa13008871484e5f88fdb0f9f744ff7", + "cursor": "7bdcb1381c7cb55c7fd602545b3ddc4461b19c43", "_cursor_note": "cursor = last upstream commit ported into b24ui (oldest-first, manual cadence). sync_enabled stays false until Phase 2 (porter workflow #67 + CLAUDE_CODE_OAUTH_TOKEN) is wired and trusted. `processed` is maintained per port from now on (backfilled #68-#72 on 2026-06-09).", "stats": { "queue_depth": 0, @@ -929,10 +929,16 @@ "summary": "feat(unplugin): pre-bundle used icons into the Vue/Vite build (#6635) — NO-OP: Vue/Vite sibling of 8d46034 (@nuxt/icon client bundle). New IconsPlugin (src/plugins/icons.ts) emitting virtual:nuxt-ui-icons + runtime/vue/plugins/icons.ts (@iconify/vue addIcon) + types/icons.d.ts + utils/icons.ts; unplugin.ts +icon.clientBundle option (from @nuxt/icon ModuleOptions) + registers IconsPlugin; plugins.ts unshifts icons plugin. All @nuxt/icon+@iconify+@iconify-json. b24ui uses @bitrix24/b24icons-vue components: no @nuxt/icon/@iconify deps, none of the icon files, and b24ui's unplugin.ts has no @nuxt/icon import/icon option/IconsPlugin and plugins.ts registers no icon plugin. Nothing to wire. Same basis as #69/#219/#8d46034. Bookkeeping only" }, "d0581cf88fa13008871484e5f88fdb0f9f744ff7": { + "pr": 254, + "b24ui_sha": "eb0990c5", + "decision": "port", + "summary": "test(ChatPrompt): avoid using fake timers before suspended (#6688) — test-only: move vi.useFakeTimers() from before mountSuspended() to after it in the 're-enables submit after compositionend cooldown' case so fake timers don't interfere with the async suspension lifecycle. Direct 1:1 (b24ui matched). No src change, no snapshot churn. Tests 5289" + }, + "7bdcb1381c7cb55c7fd602545b3ddc4461b19c43": { "pr": null, "b24ui_sha": "pending-merge", "decision": "port", - "summary": "test(ChatPrompt): avoid using fake timers before suspended (#6688) — test-only: move vi.useFakeTimers() from before mountSuspended() to after it in the 're-enables submit after compositionend cooldown' case so fake timers don't interfere with the async suspension lifecycle. Direct 1:1 (b24ui matched). No src change, no snapshot churn. Tests 5289" + "summary": "feat(Prompt): add claude action (#6693) — prose/Prompt.vue: +claude action; copy now always shown (default actions->[], +computed actions=[...new Set(['copy',...props.actions])]); +openInClaude (claude://code/new?q=), openIn* condensed to encodeURIComponent one-liners; template v-if props.actions->actions computed + Claude B24Button. Docs prompt.md updated (copy always; example cursor+claude). Adapted (b24ui naming). DEVIATION: upstream icon=i-simple-icons-claude (iconify); b24ui has no @nuxt/icon/Claude b24icon, so added inline ClaudeIcon SVG to dictionary/icons.ts (simple-icons claude path, verbatim) mirroring existing CursorIcon/WindsurfIcon; button color air-secondary-accent-2. 14 ProsePrompt snapshots (benign: claude v-if placeholder + copy always via computed). Tests 5289" } } } diff --git a/docs/content/docs/4.typography/prompt.md b/docs/content/docs/4.typography/prompt.md index 142ee5b78..abfa7aea7 100644 --- a/docs/content/docs/4.typography/prompt.md +++ b/docs/content/docs/4.typography/prompt.md @@ -38,7 +38,7 @@ slots: ### Actions -Use the `actions` prop to control which buttons are displayed. Defaults to `["copy"]`. Available actions are `copy`, `cursor` and `windsurf`. +Use the `actions` prop to display additional buttons. The `copy` button is always displayed, available actions are `cursor`, `windsurf` and `claude`. ::component-code{slug="prompt" prose} --- @@ -49,9 +49,8 @@ hide: props: description: Add a color mode toggle. actions: - - copy - cursor - - windsurf + - claude class: 'w-full my-0' slots: default: | diff --git a/src/runtime/components/prose/Prompt.vue b/src/runtime/components/prose/Prompt.vue index 28fd73f46..51825aab4 100644 --- a/src/runtime/components/prose/Prompt.vue +++ b/src/runtime/components/prose/Prompt.vue @@ -22,9 +22,10 @@ export interface ProsePromptProps { */ iconName?: string /** + * The `copy` action is always displayed, list any additional actions to show alongside it. * @defaultValue ['copy'] */ - actions?: ('copy' | 'cursor' | 'windsurf')[] + actions?: ('copy' | 'cursor' | 'windsurf' | 'claude')[] class?: any b24ui?: ProsePrompt['slots'] } @@ -48,7 +49,7 @@ import B24Button from '../Button.vue' defineOptions({ inheritAttrs: false }) const _props = withDefaults(defineProps(), { - actions: () => ['copy'] + actions: () => [] }) defineSlots() @@ -63,6 +64,9 @@ const bodyRef = useTemplateRef('bodyRef') // eslint-disable-next-line vue/no-dupe-keys const b24ui = computed(() => tv({ extend: theme, ...(appConfig.b24ui?.prose?.prompt || {}) })()) +// eslint-disable-next-line vue/no-dupe-keys +const actions = computed(() => [...new Set(['copy', ...props.actions])]) + const iconFromIconName = computed(() => resolveIcon(props.iconName)) function getPromptText() { @@ -74,17 +78,15 @@ function copyPrompt() { } function openInCursor() { - const url = new URL('cursor://anysphere.cursor-deeplink/prompt') - url.searchParams.set('text', getPromptText()) - - window.open(url.toString(), '_self') + window.open(`cursor://anysphere.cursor-deeplink/prompt?text=${encodeURIComponent(getPromptText())}`, '_self') } function openInWindsurf() { - const url = new URL('windsurf://cascade/newChat') - url.searchParams.set('prompt', getPromptText()) + window.open(`windsurf://cascade/newChat?prompt=${encodeURIComponent(getPromptText())}`, '_self') +} - window.open(url.toString(), '_self') +function openInClaude() { + window.open(`claude://code/new?q=${encodeURIComponent(getPromptText())}`, '_self') } @@ -114,7 +116,7 @@ function openInWindsurf() {
+ +
diff --git a/src/runtime/dictionary/icons.ts b/src/runtime/dictionary/icons.ts index dca409909..d35b9286a 100644 --- a/src/runtime/dictionary/icons.ts +++ b/src/runtime/dictionary/icons.ts @@ -83,6 +83,18 @@ const WindsurfIcon: IconComponent = () => h('svg', { }) ]) +const ClaudeIcon: IconComponent = () => h('svg', { + 'xmlns': 'http://www.w3.org/2000/svg', + 'viewBox': '0 0 24 24', + 'aria-hidden': 'true', + 'data-slot': 'icon' +}, [ + h('path', { + fill: 'currentColor', + d: 'm4.7144 15.9555 4.7174-2.6471.079-.2307-.079-.1275h-.2307l-.7893-.0486-2.6956-.0729-2.3375-.0971-2.2646-.1214-.5707-.1215-.5343-.7042.0546-.3522.4797-.3218.686.0608 1.5179.1032 2.2767.1578 1.6514.0972 2.4468.255h.3886l.0546-.1579-.1336-.0971-.1032-.0972L6.973 9.8356l-2.55-1.6879-1.3356-.9714-.7225-.4918-.3643-.4614-.1578-1.0078.6557-.7225.8803.0607.2246.0607.8925.686 1.9064 1.4754 2.4893 1.8336.3643.3035.1457-.1032.0182-.0728-.164-.2733-1.3539-2.4467-1.445-2.4893-.6435-1.032-.17-.6194c-.0607-.255-.1032-.4674-.1032-.7285L6.287.1335 6.6997 0l.9957.1336.419.3642.6192 1.4147 1.0018 2.2282 1.5543 3.0296.4553.8985.2429.8318.091.255h.1579v-.1457l.1275-1.706.2368-2.0947.2307-2.6957.0789-.7589.3764-.9107.7468-.4918.5828.2793.4797.686-.0668.4433-.2853 1.8517-.5586 2.9021-.3643 1.9429h.2125l.2429-.2429.9835-1.3053 1.6514-2.0643.7286-.8196.85-.9046.5464-.4311h1.0321l.759 1.1293-.34 1.1657-1.0625 1.3478-.8804 1.1414-1.2628 1.7-.7893 1.36.0729.1093.1882-.0183 2.8535-.607 1.5421-.2794 1.8396-.3157.8318.3886.091.3946-.3278.8075-1.967.4857-2.3072.4614-3.4364.8136-.0425.0304.0486.0607 1.5482.1457.6618.0364h1.621l3.0175.2247.7892.522.4736.6376-.079.4857-1.2142.6193-1.6393-.3886-3.825-.9107-1.3113-.3279h-.1822v.1093l1.0929 1.0686 2.0035 1.8092 2.5075 2.3314.1275.5768-.3218.4554-.34-.0486-2.2039-1.6575-.85-.7468-1.9246-1.621h-.1275v.17l.4432.6496 2.3436 3.5214.1214 1.0807-.17.3521-.6071.2125-.6679-.1214-1.3721-1.9246L14.38 17.959l-1.1414-1.9428-.1397.079-.674 7.2552-.3156.3703-.7286.2793-.6071-.4614-.3218-.7468.3218-1.4753.3886-1.9246.3157-1.53.2853-1.9004.17-.6314-.0121-.0425-.1397.0182-1.4328 1.9672-2.1796 2.9446-1.7243 1.8456-.4128.164-.7164-.3704.0667-.6618.4008-.5889 2.386-3.0357 1.4389-1.882.929-1.0868-.0062-.1579h-.0546l-6.3385 4.1164-1.1293.1457-.4857-.4554.0608-.7467.2307-.2429 1.9064-1.3114Z' + }) +]) + export default { arrowLeft: ArrowToTheLeftIcon, arrowRight: ArrowToTheRightIcon, @@ -139,5 +151,6 @@ export default { EncloseTextInCodeTagIcon, // source / "View code" CTA PlayLIcon, // "Try it" / playground / REPL CTA CursorIcon, // Cursor IDE — open prompt in app - WindsurfIcon // Windsurf IDE — open prompt in app + WindsurfIcon, // Windsurf IDE — open prompt in app + ClaudeIcon // Claude Code — open prompt in app } diff --git a/test/components/__snapshots__/ProsePrompt-vue.spec.ts.snap b/test/components/__snapshots__/ProsePrompt-vue.spec.ts.snap index 93e5c2302..e054c9e2a 100644 --- a/test/components/__snapshots__/ProsePrompt-vue.spec.ts.snap +++ b/test/components/__snapshots__/ProsePrompt-vue.spec.ts.snap @@ -29,7 +29,9 @@ exports[`ProsePrompt > renders with actions correctly 1`] = ` Open in Windsurf - + + + " `; @@ -51,6 +53,7 @@ exports[`ProsePrompt > renders with b24ui correctly 1`] = ` + " `; @@ -73,6 +76,7 @@ exports[`ProsePrompt > renders with class correctly 1`] = ` + " `; @@ -95,6 +99,7 @@ exports[`ProsePrompt > renders with default slot correctly 1`] = ` + " `; @@ -117,6 +122,7 @@ exports[`ProsePrompt > renders with description correctly 1`] = ` + " `; @@ -140,6 +146,7 @@ exports[`ProsePrompt > renders with icon correctly 1`] = ` + " `; @@ -164,6 +171,7 @@ exports[`ProsePrompt > renders with iconName correctly 1`] = ` + " `; diff --git a/test/components/__snapshots__/ProsePrompt.spec.ts.snap b/test/components/__snapshots__/ProsePrompt.spec.ts.snap index 93e5c2302..e054c9e2a 100644 --- a/test/components/__snapshots__/ProsePrompt.spec.ts.snap +++ b/test/components/__snapshots__/ProsePrompt.spec.ts.snap @@ -29,7 +29,9 @@ exports[`ProsePrompt > renders with actions correctly 1`] = ` Open in Windsurf - + + + " `; @@ -51,6 +53,7 @@ exports[`ProsePrompt > renders with b24ui correctly 1`] = ` + " `; @@ -73,6 +76,7 @@ exports[`ProsePrompt > renders with class correctly 1`] = ` + " `; @@ -95,6 +99,7 @@ exports[`ProsePrompt > renders with default slot correctly 1`] = ` + " `; @@ -117,6 +122,7 @@ exports[`ProsePrompt > renders with description correctly 1`] = ` + " `; @@ -140,6 +146,7 @@ exports[`ProsePrompt > renders with icon correctly 1`] = ` + " `; @@ -164,6 +171,7 @@ exports[`ProsePrompt > renders with iconName correctly 1`] = ` + " `;