diff --git a/src/client/SideCardSection.module.css b/src/client/SideCardSection.module.css index 77ea75e..18f9823 100644 --- a/src/client/SideCardSection.module.css +++ b/src/client/SideCardSection.module.css @@ -555,16 +555,26 @@ outline-offset: 1px; } +/* The plugin name: a BUTTON (not an anchor — an anchor would be caught by + the sidebar link takeover at document capture, ignoring target=_blank) + styled like a link; opens the repo in a real new browser tab. */ .pluginName { + appearance: none; min-width: 0; + padding: 0; + border: 0; + background: transparent; + font: inherit; font-size: 13px; line-height: 20px; font-weight: 600; color: var(--dsw-alias-label-primary); + text-align: left; text-decoration: none; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; + cursor: pointer; } .pluginName:hover { diff --git a/src/client/add-plugin-modal.tsx b/src/client/add-plugin-modal.tsx index a2d3f3c..762353f 100644 --- a/src/client/add-plugin-modal.tsx +++ b/src/client/add-plugin-modal.tsx @@ -47,19 +47,23 @@ export function PluginListBody(props: { service: BetterSidebarService; kind: Plu // Which entry's copy button currently shows the "已复制" feedback. const [copiedId, setCopiedId] = useState(null) - /** Copy the entry's install script to the clipboard (best-effort) and - * flash the button's "已复制" label for a moment. Never closes anything, - * never throws outward. */ - const copy = (entry: PluginEntry): void => { - void writeClipboard(entry.install) + /** Copy the entry's install script to the clipboard and flash the button's + * "已复制" label for a moment. The feedback ONLY appears after a + * successful write — when the clipboard is unavailable or denied + * (writeClipboard resolves false) nothing is shown, so the user is never + * told to paste a command that was not placed on the clipboard. Never + * closes anything, never throws outward. */ + const copy = async (entry: PluginEntry): Promise => { + const written = await writeClipboard(entry.install) + if (!written) return setCopiedId(entry.id) window.setTimeout(() => { setCopiedId(current => (current === entry.id ? null : current)) }, COPIED_FEEDBACK_MS) } - /** Open the plugin's repo in a REAL new browser tab (a button, so the - * sidebar link takeover cannot reroute it). */ + /** Open the plugin's repo in a REAL new browser tab (window.open — a + * button, so the sidebar link takeover cannot reroute it). */ const jump = (entry: PluginEntry): void => { window.open(entry.url, '_blank', 'noopener') } @@ -84,9 +88,18 @@ export function PluginListBody(props: { service: BetterSidebarService; kind: Plu {catalogOf(kind).map(entry => (
- + {/* The name is a BUTTON on the same window.open path as the + jump button: as an anchor it would be caught by the + document-capture link takeover (which ignores + target=_blank) and land in the sidebar browser. */} +