@huaweidevtools/aishell-dsh-brand 0.0.3 → 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/client.js +696 -32
- package/lib/types/client/Brand.d.ts +39 -2
- package/lib/types/client/SuggestionCards.d.ts +46 -0
- package/lib/types/client/carousel.d.ts +96 -0
- package/lib/types/client/index.d.ts +1 -1
- package/lib/types/client/locales.d.ts +66 -0
- package/lib/types/client/suggestion-icons.d.ts +45 -0
- package/lib/types/client/suggestions.d.ts +64 -0
- package/package.json +8 -6
package/lib/client.js
CHANGED
|
@@ -25,9 +25,10 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
25
25
|
|
|
26
26
|
//#endregion
|
|
27
27
|
const react_jsx_runtime = __toESM(require("react/jsx-runtime"));
|
|
28
|
+
const react = __toESM(require("react"));
|
|
28
29
|
|
|
29
30
|
//#region \0dsh-css:/home/eushing/opensource/aishell-dsh-plugins/packages/aishell-brand/src/client/brand.module.css.mjs
|
|
30
|
-
const css = ".NP1U9q_mark{background:url(data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgNDQgNDQiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSI0NC4wMDAwMDAiIGhlaWdodD0iNDQuMDAwMDAwIiBmaWxsPSJub25lIj4KCTxkZWZzPgoJCTxsaW5lYXJHcmFkaWVudCBpZD0icGFpbnRfbGluZWFyXzAiIHgxPSIzOC41IiB4Mj0iMi4xOTk5OTY5NSIgeTE9IjEuOTA3MzQ4NjNlLTA2IiB5Mj0iMzkuNTk5OTkwOCIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiPgoJCQk8c3RvcCBzdG9wLWNvbG9yPSJyZ2IoNTMsMTM3LDI1NSkiIG9mZnNldD0iMCIgc3RvcC1vcGFjaXR5PSIxIiAvPgoJCQk8c3RvcCBzdG9wLWNvbG9yPSJyZ2IoMTY5LDM4LDI1NSkiIG9mZnNldD0iMSIgc3RvcC1vcGFjaXR5PSIxIiAvPgoJCTwvbGluZWFyR3JhZGllbnQ+Cgk8L2RlZnM+Cgk8cmVjdCBpZD0iaWNvbl9BSVNoZWxsIiB3aWR0aD0iNDQuMDAwMDAwIiBoZWlnaHQ9IjQ0LjAwMDAwMCIgeD0iMC4wMDAwMDAiIHk9IjAuMDAwMDAwIiBmaWxsPSJyZ2IoMjU1LDI1NSwyNTUpIiBmaWxsLW9wYWNpdHk9IjAiIC8+Cgk8cGF0aCBpZD0i5ZCI5bm2IiBkPSJNMzcuNDU3NiAwLjI5OTczOEMzNy4zNzc1IDAuMTM5ODc3IDM3LjI4NjEgMC4wNDI4MTk2IDM3LjE4MzIgMC4wMDg1NjM5M0MzNy4wOTE3IC0wLjAxNDI3MzIgMzcuMDA2IDAuMDA4NTYzOTQgMzYuOTI1OSAwLjA3NzA3NTRDMzYuODQ1OSAwLjE0NTU4NyAzNi43ODg3IDAuMjE5ODA4IDM2Ljc1NDUgMC4yOTk3MzhDMzYuNDU3MiAxLjg2NDA4IDM1LjczNjkgMy4yMTcxOCAzNC41OTM3IDQuMzU5MDRDMzMuNDYxOCA1LjQ4OTQ4IDMyLjA5NTYgNi4yMjAyNyAzMC40OTUgNi41NTE0MUMzMC4zOTIxIDYuNTc0MjQgMzAuMzE3OCA2LjY0Mjc1IDMwLjI3MiA2Ljc1Njk0QzMwLjIzNzcgNi44NzExMyAzMC4yNDM1IDYuOTczODkgMzAuMjg5MiA3LjA2NTI0QzMwLjM0NjQgNy4xNTY1OSAzMC40MTUgNy4yMDIyNiAzMC40OTUgNy4yMDIyNkMzMS4yMDc4IDcuMzUyOTYgMzEuODc3OSA3LjU4NzU5IDMyLjUwNTUgNy45MDYxOEwzMi41MDU1IDcuOTA2MkwzMi41MDU2IDcuOTA2MjNDMzMuMjU3IDguMjg3NzEgMzMuOTQ3MyA4Ljc4OTU1IDM0LjU3NjUgOS40MTE3NkMzNS43MzEyIDEwLjU0MjIgMzYuNDU3MiAxMS44ODk2IDM2Ljc1NDUgMTMuNDUzOUMzNi44MTE2IDEzLjU5MSAzNi44OTc0IDEzLjY4MjMgMzcuMDExNyAxMy43MjhDMzcuMTE0NiAxMy43NjIyIDM3LjIwNjEgMTMuNzU2NSAzNy4yODYxIDEzLjcxMDlDMzcuMzc3NSAxMy42NTM4IDM3LjQzNDcgMTMuNTY4MSAzNy40NTc2IDEzLjQ1MzlDMzcuNzg5MSAxMS44ODk2IDM4LjUxNTEgMTAuNTQyMiAzOS42MzU1IDkuNDExNzZDNDAuNzY3NCA4LjI2OTkgNDIuMTI3OSA3LjUzMzQgNDMuNzE3IDcuMjAyMjZDNDMuODE5OSA3LjE3OTQzIDQzLjkgNy4xMjIzMyA0My45NTcxIDcuMDMwOTlDNDQuMDE0MyA2LjkyODIyIDQ0LjAxNDMgNi44MzExNiA0My45NTcxIDYuNzM5ODFDNDMuOSA2LjYzNzA1IDQzLjgxOTkgNi41NzQyNCA0My43MTcgNi41NTE0MUM0Mi4xNTA3IDYuMjIwMjcgNDAuNzk1OSA1LjQ4OTQ4IDM5LjY1MjcgNC4zNTkwNEMzOC41MjA4IDMuMjE3MTggMzcuNzg5MSAxLjg2NDA4IDM3LjQ1NzYgMC4yOTk3MzhaTTQyLjYyNSAxNi40OTk5TDQyLjYyNSAzM0M0Mi42MjUgMzMuOTQ5MyA0Mi40NTcyIDM0LjgyOSA0Mi4xMjE2IDM1LjYzOTJDNDEuNzg2IDM2LjQ0OTUgNDEuMjgyNiAzNy4xOTAyIDQwLjYxMTQgMzcuODYxNEMzOS45NDAyIDM4LjUzMjYgMzkuMTk5NCAzOS4wMzYgMzguMzg5MiAzOS4zNzE2QzM3LjU3OSAzOS43MDcyIDM2LjY5OTIgMzkuODc1IDM1Ljc1IDM5Ljg3NUwxMC45OTk5IDM5Ljg3NUw4LjI0OTk1IDM5Ljg3NUM3LjMwMDczIDM5Ljg3NSA2LjQyMTAyIDM5LjcwNzIgNS42MTA4MSAzOS4zNzE2QzQuODAwNTggMzkuMDM2IDQuMDU5ODUgMzguNTMyNiAzLjM4ODYzIDM3Ljg2MTRDMi43MTc0MiAzNy4xOTAyIDIuMjE0MDIgMzYuNDQ5NCAxLjg3ODQxIDM1LjYzOTJDMS41NDI4IDM0LjgyOSAxLjM3NSAzMy45NDkzIDEuMzc1IDMzTDEuMzc1IDExQzEuMzc1IDEwLjA1MDggMS41NDI4IDkuMTcxMDYgMS44Nzg0IDguMzYwODNMMS44Nzg0MSA4LjM2MDgyQzIuMjE0MDIgNy41NTA1OSAyLjcxNzQzIDYuODA5ODcgMy4zODg2NCA2LjEzODY2QzQuMDU5ODUgNS40Njc0NSA0LjgwMDU3IDQuOTY0MDQgNS42MTA3OSA0LjYyODQzTDUuNjEwOCA0LjYyODQzQzYuNDIxMDMgNC4yOTI4MiA3LjMwMDc2IDQuMTI1MDIgOC4yNSA0LjEyNTAyTDI3LjQ5OTkgNC4xMjVDMjguMjY5OSA0LjEyNSAyOC44NzQ5IDQuNzMgMjguODc0OSA1LjVDMjguODc0OSA2LjI3IDI4LjI2OTkgNi44NzUgMjcuNDk5OSA2Ljg3NUw4LjI1IDYuODc1MDJDNy42ODA0NSA2Ljg3NTAyIDcuMTUyNjEgNi45NzU3IDYuNjY2NDggNy4xNzcwNkM2LjE4MDM0IDcuMzc4NDMgNS43MzU5MSA3LjY4MDQ3IDUuMzMzMTggOC4wODMyQzQuOTMwNDYgOC40ODU5MyA0LjYyODQxIDguOTMwMzYgNC40MjcwNSA5LjQxNjQ5QzQuMjI1NjggOS45MDI2MyA0LjEyNSAxMC40MzA1IDQuMTI1IDExTDQuMTI1IDMzQzQuMTI1IDMzLjU2OTYgNC4yMjU2OCAzNC4wOTc0IDQuNDI3MDUgMzQuNTgzNUM0LjYyODQxIDM1LjA2OTcgNC45MzA0NSAzNS41MTQxIDUuMzMzMTcgMzUuOTE2OEM1LjczNTg4IDM2LjMxOTUgNi4xODAyOCAzNi42MjE2IDYuNjY2MzkgMzYuODIyOUM3LjE1MjU2IDM3LjAyNDMgNy42ODA0MiAzNy4xMjUgOC4yNDk5OSAzNy4xMjVMMTAuOTk5OSAzNy4xMjVMMzUuNzUgMzcuMTI1QzM2LjMxOTUgMzcuMTI1IDM2Ljg0NzQgMzcuMDI0MyAzNy4zMzM1IDM2LjgyM0MzNy44MTk3IDM2LjYyMTYgMzguMjY0MSAzNi4zMTk2IDM4LjY2NjggMzUuOTE2OEMzOS4wNjk1IDM1LjUxNDEgMzkuMzcxNiAzNS4wNjk3IDM5LjU3MyAzNC41ODM1QzM5Ljc3NDMgMzQuMDk3NCAzOS44NzUgMzMuNTY5NiAzOS44NzUgMzNMMzkuODc1IDE2LjQ5OTlDMzkuODc1IDE1LjcyOTkgNDAuNDggMTUuMTI0OSA0MS4yNSAxNS4xMjQ5QzQyLjAyIDE1LjEyNDkgNDIuNjI1IDE1LjcyOTkgNDIuNjI1IDE2LjQ5OTlaTTEwLjAyNzcgMTIuNzc3N0MxMC41NzIyIDEyLjIzMzMgMTEuNDI3OCAxMi4yMzMzIDExLjk3MjMgMTIuNzc3N0wyMC4yMjIyIDIxLjAyNzdDMjAuNDkwNyAyMS4yOTYyIDIwLjYyNDkgMjEuNjIwMyAyMC42MjQ5IDIyQzIwLjYyNDkgMjIuMzc5NyAyMC40OTA3IDIyLjcwMzcgMjAuMjIyMiAyMi45NzIyTDExLjk3MjIgMzEuMjIyM0MxMS40Mjc3IDMxLjc2NjggMTAuNTcyMSAzMS43NjY4IDEwLjAyNzcgMzEuMjIyM0M5LjQ4MzE4IDMwLjY3NzkgOS40ODMxNyAyOS44MjIzIDEwLjAyNzYgMjkuMjc3OEwxNy4zMDU0IDIyTDEwLjAyNzcgMTQuNzIyM0M5LjQ4MzI1IDE0LjE3NzggOS40ODMyNiAxMy4zMjIyIDEwLjAyNzcgMTIuNzc3N1pNMjAuNjI1IDI4Ljg3NUMyMC42MjUgMjguMTA1IDIxLjIzIDI3LjUgMjIgMjcuNUwzMyAyNy41QzMzLjc3IDI3LjUgMzQuMzc1IDI4LjEwNSAzNC4zNzUgMjguODc1QzM0LjM3NSAyOS42NDUgMzMuNzcgMzAuMjUgMzMgMzAuMjVMMjIgMzAuMjVDMjEuMjMgMzAuMjUgMjAuNjI1IDI5LjY0NSAyMC42MjUgMjguODc1WiIgZmlsbD0icmdiKDAsMCwwKSIgZmlsbC1vcGFjaXR5PSIwIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIC8+Cgk8cGF0aCBpZD0i5ZCI5bm2IiBkPSJNMzcuNDU3NiAwLjI5OTczOEMzNy4zNzc1IDAuMTM5ODc3IDM3LjI4NjEgMC4wNDI4MTk2IDM3LjE4MzIgMC4wMDg1NjM5M0MzNy4wOTE3IC0wLjAxNDI3MzIgMzcuMDA2IDAuMDA4NTYzOTQgMzYuOTI1OSAwLjA3NzA3NTRDMzYuODQ1OSAwLjE0NTU4NyAzNi43ODg3IDAuMjE5ODA4IDM2Ljc1NDUgMC4yOTk3MzhDMzYuNDU3MiAxLjg2NDA4IDM1LjczNjkgMy4yMTcxOCAzNC41OTM3IDQuMzU5MDRDMzMuNDYxOCA1LjQ4OTQ4IDMyLjA5NTYgNi4yMjAyNyAzMC40OTUgNi41NTE0MUMzMC4zOTIxIDYuNTc0MjQgMzAuMzE3OCA2LjY0Mjc1IDMwLjI3MiA2Ljc1Njk0QzMwLjIzNzcgNi44NzExMyAzMC4yNDM1IDYuOTczODkgMzAuMjg5MiA3LjA2NTI0QzMwLjM0NjQgNy4xNTY1OSAzMC40MTUgNy4yMDIyNiAzMC40OTUgNy4yMDIyNkMzMS4yMDc4IDcuMzUyOTYgMzEuODc3OSA3LjU4NzU5IDMyLjUwNTUgNy45MDYxOEwzMi41MDU1IDcuOTA2MkwzMi41MDU2IDcuOTA2MjNDMzMuMjU3IDguMjg3NzEgMzMuOTQ3MyA4Ljc4OTU1IDM0LjU3NjUgOS40MTE3NkMzNS43MzEyIDEwLjU0MjIgMzYuNDU3MiAxMS44ODk2IDM2Ljc1NDUgMTMuNDUzOUMzNi44MTE2IDEzLjU5MSAzNi44OTc0IDEzLjY4MjMgMzcuMDExNyAxMy43MjhDMzcuMTE0NiAxMy43NjIyIDM3LjIwNjEgMTMuNzU2NSAzNy4yODYxIDEzLjcxMDlDMzcuMzc3NSAxMy42NTM4IDM3LjQzNDcgMTMuNTY4MSAzNy40NTc2IDEzLjQ1MzlDMzcuNzg5MSAxMS44ODk2IDM4LjUxNTEgMTAuNTQyMiAzOS42MzU1IDkuNDExNzZDNDAuNzY3NCA4LjI2OTkgNDIuMTI3OSA3LjUzMzQgNDMuNzE3IDcuMjAyMjZDNDMuODE5OSA3LjE3OTQzIDQzLjkgNy4xMjIzMyA0My45NTcxIDcuMDMwOTlDNDQuMDE0MyA2LjkyODIyIDQ0LjAxNDMgNi44MzExNiA0My45NTcxIDYuNzM5ODFDNDMuOSA2LjYzNzA1IDQzLjgxOTkgNi41NzQyNCA0My43MTcgNi41NTE0MUM0Mi4xNTA3IDYuMjIwMjcgNDAuNzk1OSA1LjQ4OTQ4IDM5LjY1MjcgNC4zNTkwNEMzOC41MjA4IDMuMjE3MTggMzcuNzg5MSAxLjg2NDA4IDM3LjQ1NzYgMC4yOTk3MzhaTTQyLjYyNSAxNi40OTk5TDQyLjYyNSAzM0M0Mi42MjUgMzMuOTQ5MyA0Mi40NTcyIDM0LjgyOSA0Mi4xMjE2IDM1LjYzOTJDNDEuNzg2IDM2LjQ0OTUgNDEuMjgyNiAzNy4xOTAyIDQwLjYxMTQgMzcuODYxNEMzOS45NDAyIDM4LjUzMjYgMzkuMTk5NCAzOS4wMzYgMzguMzg5MiAzOS4zNzE2QzM3LjU3OSAzOS43MDcyIDM2LjY5OTIgMzkuODc1IDM1Ljc1IDM5Ljg3NUwxMC45OTk5IDM5Ljg3NUw4LjI0OTk1IDM5Ljg3NUM3LjMwMDczIDM5Ljg3NSA2LjQyMTAyIDM5LjcwNzIgNS42MTA4MSAzOS4zNzE2QzQuODAwNTggMzkuMDM2IDQuMDU5ODUgMzguNTMyNiAzLjM4ODYzIDM3Ljg2MTRDMi43MTc0MiAzNy4xOTAyIDIuMjE0MDIgMzYuNDQ5NCAxLjg3ODQxIDM1LjYzOTJDMS41NDI4IDM0LjgyOSAxLjM3NSAzMy45NDkzIDEuMzc1IDMzTDEuMzc1IDExQzEuMzc1IDEwLjA1MDggMS41NDI4IDkuMTcxMDYgMS44Nzg0IDguMzYwODNMMS44Nzg0MSA4LjM2MDgyQzIuMjE0MDIgNy41NTA1OSAyLjcxNzQzIDYuODA5ODcgMy4zODg2NCA2LjEzODY2QzQuMDU5ODUgNS40Njc0NSA0LjgwMDU3IDQuOTY0MDQgNS42MTA3OSA0LjYyODQzTDUuNjEwOCA0LjYyODQzQzYuNDIxMDMgNC4yOTI4MiA3LjMwMDc2IDQuMTI1MDIgOC4yNSA0LjEyNTAyTDI3LjQ5OTkgNC4xMjVDMjguMjY5OSA0LjEyNSAyOC44NzQ5IDQuNzMgMjguODc0OSA1LjVDMjguODc0OSA2LjI3IDI4LjI2OTkgNi44NzUgMjcuNDk5OSA2Ljg3NUw4LjI1IDYuODc1MDJDNy42ODA0NSA2Ljg3NTAyIDcuMTUyNjEgNi45NzU3IDYuNjY2NDggNy4xNzcwNkM2LjE4MDM0IDcuMzc4NDMgNS43MzU5MSA3LjY4MDQ3IDUuMzMzMTggOC4wODMyQzQuOTMwNDYgOC40ODU5MyA0LjYyODQxIDguOTMwMzYgNC40MjcwNSA5LjQxNjQ5QzQuMjI1NjggOS45MDI2MyA0LjEyNSAxMC40MzA1IDQuMTI1IDExTDQuMTI1IDMzQzQuMTI1IDMzLjU2OTYgNC4yMjU2OCAzNC4wOTc0IDQuNDI3MDUgMzQuNTgzNUM0LjYyODQxIDM1LjA2OTcgNC45MzA0NSAzNS41MTQxIDUuMzMzMTcgMzUuOTE2OEM1LjczNTg4IDM2LjMxOTUgNi4xODAyOCAzNi42MjE2IDYuNjY2MzkgMzYuODIyOUM3LjE1MjU2IDM3LjAyNDMgNy42ODA0MiAzNy4xMjUgOC4yNDk5OSAzNy4xMjVMMTAuOTk5OSAzNy4xMjVMMzUuNzUgMzcuMTI1QzM2LjMxOTUgMzcuMTI1IDM2Ljg0NzQgMzcuMDI0MyAzNy4zMzM1IDM2LjgyM0MzNy44MTk3IDM2LjYyMTYgMzguMjY0MSAzNi4zMTk2IDM4LjY2NjggMzUuOTE2OEMzOS4wNjk1IDM1LjUxNDEgMzkuMzcxNiAzNS4wNjk3IDM5LjU3MyAzNC41ODM1QzM5Ljc3NDMgMzQuMDk3NCAzOS44NzUgMzMuNTY5NiAzOS44NzUgMzNMMzkuODc1IDE2LjQ5OTlDMzkuODc1IDE1LjcyOTkgNDAuNDggMTUuMTI0OSA0MS4yNSAxNS4xMjQ5QzQyLjAyIDE1LjEyNDkgNDIuNjI1IDE1LjcyOTkgNDIuNjI1IDE2LjQ5OTlaTTEwLjAyNzcgMTIuNzc3N0MxMC41NzIyIDEyLjIzMzMgMTEuNDI3OCAxMi4yMzMzIDExLjk3MjMgMTIuNzc3N0wyMC4yMjIyIDIxLjAyNzdDMjAuNDkwNyAyMS4yOTYyIDIwLjYyNDkgMjEuNjIwMyAyMC42MjQ5IDIyQzIwLjYyNDkgMjIuMzc5NyAyMC40OTA3IDIyLjcwMzcgMjAuMjIyMiAyMi45NzIyTDExLjk3MjIgMzEuMjIyM0MxMS40Mjc3IDMxLjc2NjggMTAuNTcyMSAzMS43NjY4IDEwLjAyNzcgMzEuMjIyM0M5LjQ4MzE4IDMwLjY3NzkgOS40ODMxNyAyOS44MjIzIDEwLjAyNzYgMjkuMjc3OEwxNy4zMDU0IDIyTDEwLjAyNzcgMTQuNzIyM0M5LjQ4MzI1IDE0LjE3NzggOS40ODMyNiAxMy4zMjIyIDEwLjAyNzcgMTIuNzc3N1pNMjAuNjI1IDI4Ljg3NUMyMC42MjUgMjguMTA1IDIxLjIzIDI3LjUgMjIgMjcuNUwzMyAyNy41QzMzLjc3IDI3LjUgMzQuMzc1IDI4LjEwNSAzNC4zNzUgMjguODc1QzM0LjM3NSAyOS42NDUgMzMuNzcgMzAuMjUgMzMgMzAuMjVMMjIgMzAuMjVDMjEuMjMgMzAuMjUgMjAuNjI1IDI5LjY0NSAyMC42MjUgMjguODc1WiIgZmlsbD0idXJsKCNwYWludF9saW5lYXJfMCkiIGZpbGwtcnVsZT0iZXZlbm9kZCIgLz4KPC9zdmc+Cg==) 50%/contain no-repeat;display:inline-block}.NP1U9q_name{vertical-align:middle;align-items:center;
|
|
31
|
+
const css = ".NP1U9q_mark{background:url(data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgNDQgNDQiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSI0NC4wMDAwMDAiIGhlaWdodD0iNDQuMDAwMDAwIiBmaWxsPSJub25lIj4KCTxkZWZzPgoJCTxsaW5lYXJHcmFkaWVudCBpZD0icGFpbnRfbGluZWFyXzAiIHgxPSIzOC41IiB4Mj0iMi4xOTk5OTY5NSIgeTE9IjEuOTA3MzQ4NjNlLTA2IiB5Mj0iMzkuNTk5OTkwOCIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiPgoJCQk8c3RvcCBzdG9wLWNvbG9yPSJyZ2IoNTMsMTM3LDI1NSkiIG9mZnNldD0iMCIgc3RvcC1vcGFjaXR5PSIxIiAvPgoJCQk8c3RvcCBzdG9wLWNvbG9yPSJyZ2IoMTY5LDM4LDI1NSkiIG9mZnNldD0iMSIgc3RvcC1vcGFjaXR5PSIxIiAvPgoJCTwvbGluZWFyR3JhZGllbnQ+Cgk8L2RlZnM+Cgk8cmVjdCBpZD0iaWNvbl9BSVNoZWxsIiB3aWR0aD0iNDQuMDAwMDAwIiBoZWlnaHQ9IjQ0LjAwMDAwMCIgeD0iMC4wMDAwMDAiIHk9IjAuMDAwMDAwIiBmaWxsPSJyZ2IoMjU1LDI1NSwyNTUpIiBmaWxsLW9wYWNpdHk9IjAiIC8+Cgk8cGF0aCBpZD0i5ZCI5bm2IiBkPSJNMzcuNDU3NiAwLjI5OTczOEMzNy4zNzc1IDAuMTM5ODc3IDM3LjI4NjEgMC4wNDI4MTk2IDM3LjE4MzIgMC4wMDg1NjM5M0MzNy4wOTE3IC0wLjAxNDI3MzIgMzcuMDA2IDAuMDA4NTYzOTQgMzYuOTI1OSAwLjA3NzA3NTRDMzYuODQ1OSAwLjE0NTU4NyAzNi43ODg3IDAuMjE5ODA4IDM2Ljc1NDUgMC4yOTk3MzhDMzYuNDU3MiAxLjg2NDA4IDM1LjczNjkgMy4yMTcxOCAzNC41OTM3IDQuMzU5MDRDMzMuNDYxOCA1LjQ4OTQ4IDMyLjA5NTYgNi4yMjAyNyAzMC40OTUgNi41NTE0MUMzMC4zOTIxIDYuNTc0MjQgMzAuMzE3OCA2LjY0Mjc1IDMwLjI3MiA2Ljc1Njk0QzMwLjIzNzcgNi44NzExMyAzMC4yNDM1IDYuOTczODkgMzAuMjg5MiA3LjA2NTI0QzMwLjM0NjQgNy4xNTY1OSAzMC40MTUgNy4yMDIyNiAzMC40OTUgNy4yMDIyNkMzMS4yMDc4IDcuMzUyOTYgMzEuODc3OSA3LjU4NzU5IDMyLjUwNTUgNy45MDYxOEwzMi41MDU1IDcuOTA2MkwzMi41MDU2IDcuOTA2MjNDMzMuMjU3IDguMjg3NzEgMzMuOTQ3MyA4Ljc4OTU1IDM0LjU3NjUgOS40MTE3NkMzNS43MzEyIDEwLjU0MjIgMzYuNDU3MiAxMS44ODk2IDM2Ljc1NDUgMTMuNDUzOUMzNi44MTE2IDEzLjU5MSAzNi44OTc0IDEzLjY4MjMgMzcuMDExNyAxMy43MjhDMzcuMTE0NiAxMy43NjIyIDM3LjIwNjEgMTMuNzU2NSAzNy4yODYxIDEzLjcxMDlDMzcuMzc3NSAxMy42NTM4IDM3LjQzNDcgMTMuNTY4MSAzNy40NTc2IDEzLjQ1MzlDMzcuNzg5MSAxMS44ODk2IDM4LjUxNTEgMTAuNTQyMiAzOS42MzU1IDkuNDExNzZDNDAuNzY3NCA4LjI2OTkgNDIuMTI3OSA3LjUzMzQgNDMuNzE3IDcuMjAyMjZDNDMuODE5OSA3LjE3OTQzIDQzLjkgNy4xMjIzMyA0My45NTcxIDcuMDMwOTlDNDQuMDE0MyA2LjkyODIyIDQ0LjAxNDMgNi44MzExNiA0My45NTcxIDYuNzM5ODFDNDMuOSA2LjYzNzA1IDQzLjgxOTkgNi41NzQyNCA0My43MTcgNi41NTE0MUM0Mi4xNTA3IDYuMjIwMjcgNDAuNzk1OSA1LjQ4OTQ4IDM5LjY1MjcgNC4zNTkwNEMzOC41MjA4IDMuMjE3MTggMzcuNzg5MSAxLjg2NDA4IDM3LjQ1NzYgMC4yOTk3MzhaTTQyLjYyNSAxNi40OTk5TDQyLjYyNSAzM0M0Mi42MjUgMzMuOTQ5MyA0Mi40NTcyIDM0LjgyOSA0Mi4xMjE2IDM1LjYzOTJDNDEuNzg2IDM2LjQ0OTUgNDEuMjgyNiAzNy4xOTAyIDQwLjYxMTQgMzcuODYxNEMzOS45NDAyIDM4LjUzMjYgMzkuMTk5NCAzOS4wMzYgMzguMzg5MiAzOS4zNzE2QzM3LjU3OSAzOS43MDcyIDM2LjY5OTIgMzkuODc1IDM1Ljc1IDM5Ljg3NUwxMC45OTk5IDM5Ljg3NUw4LjI0OTk1IDM5Ljg3NUM3LjMwMDczIDM5Ljg3NSA2LjQyMTAyIDM5LjcwNzIgNS42MTA4MSAzOS4zNzE2QzQuODAwNTggMzkuMDM2IDQuMDU5ODUgMzguNTMyNiAzLjM4ODYzIDM3Ljg2MTRDMi43MTc0MiAzNy4xOTAyIDIuMjE0MDIgMzYuNDQ5NCAxLjg3ODQxIDM1LjYzOTJDMS41NDI4IDM0LjgyOSAxLjM3NSAzMy45NDkzIDEuMzc1IDMzTDEuMzc1IDExQzEuMzc1IDEwLjA1MDggMS41NDI4IDkuMTcxMDYgMS44Nzg0IDguMzYwODNMMS44Nzg0MSA4LjM2MDgyQzIuMjE0MDIgNy41NTA1OSAyLjcxNzQzIDYuODA5ODcgMy4zODg2NCA2LjEzODY2QzQuMDU5ODUgNS40Njc0NSA0LjgwMDU3IDQuOTY0MDQgNS42MTA3OSA0LjYyODQzTDUuNjEwOCA0LjYyODQzQzYuNDIxMDMgNC4yOTI4MiA3LjMwMDc2IDQuMTI1MDIgOC4yNSA0LjEyNTAyTDI3LjQ5OTkgNC4xMjVDMjguMjY5OSA0LjEyNSAyOC44NzQ5IDQuNzMgMjguODc0OSA1LjVDMjguODc0OSA2LjI3IDI4LjI2OTkgNi44NzUgMjcuNDk5OSA2Ljg3NUw4LjI1IDYuODc1MDJDNy42ODA0NSA2Ljg3NTAyIDcuMTUyNjEgNi45NzU3IDYuNjY2NDggNy4xNzcwNkM2LjE4MDM0IDcuMzc4NDMgNS43MzU5MSA3LjY4MDQ3IDUuMzMzMTggOC4wODMyQzQuOTMwNDYgOC40ODU5MyA0LjYyODQxIDguOTMwMzYgNC40MjcwNSA5LjQxNjQ5QzQuMjI1NjggOS45MDI2MyA0LjEyNSAxMC40MzA1IDQuMTI1IDExTDQuMTI1IDMzQzQuMTI1IDMzLjU2OTYgNC4yMjU2OCAzNC4wOTc0IDQuNDI3MDUgMzQuNTgzNUM0LjYyODQxIDM1LjA2OTcgNC45MzA0NSAzNS41MTQxIDUuMzMzMTcgMzUuOTE2OEM1LjczNTg4IDM2LjMxOTUgNi4xODAyOCAzNi42MjE2IDYuNjY2MzkgMzYuODIyOUM3LjE1MjU2IDM3LjAyNDMgNy42ODA0MiAzNy4xMjUgOC4yNDk5OSAzNy4xMjVMMTAuOTk5OSAzNy4xMjVMMzUuNzUgMzcuMTI1QzM2LjMxOTUgMzcuMTI1IDM2Ljg0NzQgMzcuMDI0MyAzNy4zMzM1IDM2LjgyM0MzNy44MTk3IDM2LjYyMTYgMzguMjY0MSAzNi4zMTk2IDM4LjY2NjggMzUuOTE2OEMzOS4wNjk1IDM1LjUxNDEgMzkuMzcxNiAzNS4wNjk3IDM5LjU3MyAzNC41ODM1QzM5Ljc3NDMgMzQuMDk3NCAzOS44NzUgMzMuNTY5NiAzOS44NzUgMzNMMzkuODc1IDE2LjQ5OTlDMzkuODc1IDE1LjcyOTkgNDAuNDggMTUuMTI0OSA0MS4yNSAxNS4xMjQ5QzQyLjAyIDE1LjEyNDkgNDIuNjI1IDE1LjcyOTkgNDIuNjI1IDE2LjQ5OTlaTTEwLjAyNzcgMTIuNzc3N0MxMC41NzIyIDEyLjIzMzMgMTEuNDI3OCAxMi4yMzMzIDExLjk3MjMgMTIuNzc3N0wyMC4yMjIyIDIxLjAyNzdDMjAuNDkwNyAyMS4yOTYyIDIwLjYyNDkgMjEuNjIwMyAyMC42MjQ5IDIyQzIwLjYyNDkgMjIuMzc5NyAyMC40OTA3IDIyLjcwMzcgMjAuMjIyMiAyMi45NzIyTDExLjk3MjIgMzEuMjIyM0MxMS40Mjc3IDMxLjc2NjggMTAuNTcyMSAzMS43NjY4IDEwLjAyNzcgMzEuMjIyM0M5LjQ4MzE4IDMwLjY3NzkgOS40ODMxNyAyOS44MjIzIDEwLjAyNzYgMjkuMjc3OEwxNy4zMDU0IDIyTDEwLjAyNzcgMTQuNzIyM0M5LjQ4MzI1IDE0LjE3NzggOS40ODMyNiAxMy4zMjIyIDEwLjAyNzcgMTIuNzc3N1pNMjAuNjI1IDI4Ljg3NUMyMC42MjUgMjguMTA1IDIxLjIzIDI3LjUgMjIgMjcuNUwzMyAyNy41QzMzLjc3IDI3LjUgMzQuMzc1IDI4LjEwNSAzNC4zNzUgMjguODc1QzM0LjM3NSAyOS42NDUgMzMuNzcgMzAuMjUgMzMgMzAuMjVMMjIgMzAuMjVDMjEuMjMgMzAuMjUgMjAuNjI1IDI5LjY0NSAyMC42MjUgMjguODc1WiIgZmlsbD0icmdiKDAsMCwwKSIgZmlsbC1vcGFjaXR5PSIwIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIC8+Cgk8cGF0aCBpZD0i5ZCI5bm2IiBkPSJNMzcuNDU3NiAwLjI5OTczOEMzNy4zNzc1IDAuMTM5ODc3IDM3LjI4NjEgMC4wNDI4MTk2IDM3LjE4MzIgMC4wMDg1NjM5M0MzNy4wOTE3IC0wLjAxNDI3MzIgMzcuMDA2IDAuMDA4NTYzOTQgMzYuOTI1OSAwLjA3NzA3NTRDMzYuODQ1OSAwLjE0NTU4NyAzNi43ODg3IDAuMjE5ODA4IDM2Ljc1NDUgMC4yOTk3MzhDMzYuNDU3MiAxLjg2NDA4IDM1LjczNjkgMy4yMTcxOCAzNC41OTM3IDQuMzU5MDRDMzMuNDYxOCA1LjQ4OTQ4IDMyLjA5NTYgNi4yMjAyNyAzMC40OTUgNi41NTE0MUMzMC4zOTIxIDYuNTc0MjQgMzAuMzE3OCA2LjY0Mjc1IDMwLjI3MiA2Ljc1Njk0QzMwLjIzNzcgNi44NzExMyAzMC4yNDM1IDYuOTczODkgMzAuMjg5MiA3LjA2NTI0QzMwLjM0NjQgNy4xNTY1OSAzMC40MTUgNy4yMDIyNiAzMC40OTUgNy4yMDIyNkMzMS4yMDc4IDcuMzUyOTYgMzEuODc3OSA3LjU4NzU5IDMyLjUwNTUgNy45MDYxOEwzMi41MDU1IDcuOTA2MkwzMi41MDU2IDcuOTA2MjNDMzMuMjU3IDguMjg3NzEgMzMuOTQ3MyA4Ljc4OTU1IDM0LjU3NjUgOS40MTE3NkMzNS43MzEyIDEwLjU0MjIgMzYuNDU3MiAxMS44ODk2IDM2Ljc1NDUgMTMuNDUzOUMzNi44MTE2IDEzLjU5MSAzNi44OTc0IDEzLjY4MjMgMzcuMDExNyAxMy43MjhDMzcuMTE0NiAxMy43NjIyIDM3LjIwNjEgMTMuNzU2NSAzNy4yODYxIDEzLjcxMDlDMzcuMzc3NSAxMy42NTM4IDM3LjQzNDcgMTMuNTY4MSAzNy40NTc2IDEzLjQ1MzlDMzcuNzg5MSAxMS44ODk2IDM4LjUxNTEgMTAuNTQyMiAzOS42MzU1IDkuNDExNzZDNDAuNzY3NCA4LjI2OTkgNDIuMTI3OSA3LjUzMzQgNDMuNzE3IDcuMjAyMjZDNDMuODE5OSA3LjE3OTQzIDQzLjkgNy4xMjIzMyA0My45NTcxIDcuMDMwOTlDNDQuMDE0MyA2LjkyODIyIDQ0LjAxNDMgNi44MzExNiA0My45NTcxIDYuNzM5ODFDNDMuOSA2LjYzNzA1IDQzLjgxOTkgNi41NzQyNCA0My43MTcgNi41NTE0MUM0Mi4xNTA3IDYuMjIwMjcgNDAuNzk1OSA1LjQ4OTQ4IDM5LjY1MjcgNC4zNTkwNEMzOC41MjA4IDMuMjE3MTggMzcuNzg5MSAxLjg2NDA4IDM3LjQ1NzYgMC4yOTk3MzhaTTQyLjYyNSAxNi40OTk5TDQyLjYyNSAzM0M0Mi42MjUgMzMuOTQ5MyA0Mi40NTcyIDM0LjgyOSA0Mi4xMjE2IDM1LjYzOTJDNDEuNzg2IDM2LjQ0OTUgNDEuMjgyNiAzNy4xOTAyIDQwLjYxMTQgMzcuODYxNEMzOS45NDAyIDM4LjUzMjYgMzkuMTk5NCAzOS4wMzYgMzguMzg5MiAzOS4zNzE2QzM3LjU3OSAzOS43MDcyIDM2LjY5OTIgMzkuODc1IDM1Ljc1IDM5Ljg3NUwxMC45OTk5IDM5Ljg3NUw4LjI0OTk1IDM5Ljg3NUM3LjMwMDczIDM5Ljg3NSA2LjQyMTAyIDM5LjcwNzIgNS42MTA4MSAzOS4zNzE2QzQuODAwNTggMzkuMDM2IDQuMDU5ODUgMzguNTMyNiAzLjM4ODYzIDM3Ljg2MTRDMi43MTc0MiAzNy4xOTAyIDIuMjE0MDIgMzYuNDQ5NCAxLjg3ODQxIDM1LjYzOTJDMS41NDI4IDM0LjgyOSAxLjM3NSAzMy45NDkzIDEuMzc1IDMzTDEuMzc1IDExQzEuMzc1IDEwLjA1MDggMS41NDI4IDkuMTcxMDYgMS44Nzg0IDguMzYwODNMMS44Nzg0MSA4LjM2MDgyQzIuMjE0MDIgNy41NTA1OSAyLjcxNzQzIDYuODA5ODcgMy4zODg2NCA2LjEzODY2QzQuMDU5ODUgNS40Njc0NSA0LjgwMDU3IDQuOTY0MDQgNS42MTA3OSA0LjYyODQzTDUuNjEwOCA0LjYyODQzQzYuNDIxMDMgNC4yOTI4MiA3LjMwMDc2IDQuMTI1MDIgOC4yNSA0LjEyNTAyTDI3LjQ5OTkgNC4xMjVDMjguMjY5OSA0LjEyNSAyOC44NzQ5IDQuNzMgMjguODc0OSA1LjVDMjguODc0OSA2LjI3IDI4LjI2OTkgNi44NzUgMjcuNDk5OSA2Ljg3NUw4LjI1IDYuODc1MDJDNy42ODA0NSA2Ljg3NTAyIDcuMTUyNjEgNi45NzU3IDYuNjY2NDggNy4xNzcwNkM2LjE4MDM0IDcuMzc4NDMgNS43MzU5MSA3LjY4MDQ3IDUuMzMzMTggOC4wODMyQzQuOTMwNDYgOC40ODU5MyA0LjYyODQxIDguOTMwMzYgNC40MjcwNSA5LjQxNjQ5QzQuMjI1NjggOS45MDI2MyA0LjEyNSAxMC40MzA1IDQuMTI1IDExTDQuMTI1IDMzQzQuMTI1IDMzLjU2OTYgNC4yMjU2OCAzNC4wOTc0IDQuNDI3MDUgMzQuNTgzNUM0LjYyODQxIDM1LjA2OTcgNC45MzA0NSAzNS41MTQxIDUuMzMzMTcgMzUuOTE2OEM1LjczNTg4IDM2LjMxOTUgNi4xODAyOCAzNi42MjE2IDYuNjY2MzkgMzYuODIyOUM3LjE1MjU2IDM3LjAyNDMgNy42ODA0MiAzNy4xMjUgOC4yNDk5OSAzNy4xMjVMMTAuOTk5OSAzNy4xMjVMMzUuNzUgMzcuMTI1QzM2LjMxOTUgMzcuMTI1IDM2Ljg0NzQgMzcuMDI0MyAzNy4zMzM1IDM2LjgyM0MzNy44MTk3IDM2LjYyMTYgMzguMjY0MSAzNi4zMTk2IDM4LjY2NjggMzUuOTE2OEMzOS4wNjk1IDM1LjUxNDEgMzkuMzcxNiAzNS4wNjk3IDM5LjU3MyAzNC41ODM1QzM5Ljc3NDMgMzQuMDk3NCAzOS44NzUgMzMuNTY5NiAzOS44NzUgMzNMMzkuODc1IDE2LjQ5OTlDMzkuODc1IDE1LjcyOTkgNDAuNDggMTUuMTI0OSA0MS4yNSAxNS4xMjQ5QzQyLjAyIDE1LjEyNDkgNDIuNjI1IDE1LjcyOTkgNDIuNjI1IDE2LjQ5OTlaTTEwLjAyNzcgMTIuNzc3N0MxMC41NzIyIDEyLjIzMzMgMTEuNDI3OCAxMi4yMzMzIDExLjk3MjMgMTIuNzc3N0wyMC4yMjIyIDIxLjAyNzdDMjAuNDkwNyAyMS4yOTYyIDIwLjYyNDkgMjEuNjIwMyAyMC42MjQ5IDIyQzIwLjYyNDkgMjIuMzc5NyAyMC40OTA3IDIyLjcwMzcgMjAuMjIyMiAyMi45NzIyTDExLjk3MjIgMzEuMjIyM0MxMS40Mjc3IDMxLjc2NjggMTAuNTcyMSAzMS43NjY4IDEwLjAyNzcgMzEuMjIyM0M5LjQ4MzE4IDMwLjY3NzkgOS40ODMxNyAyOS44MjIzIDEwLjAyNzYgMjkuMjc3OEwxNy4zMDU0IDIyTDEwLjAyNzcgMTQuNzIyM0M5LjQ4MzI1IDE0LjE3NzggOS40ODMyNiAxMy4zMjIyIDEwLjAyNzcgMTIuNzc3N1pNMjAuNjI1IDI4Ljg3NUMyMC42MjUgMjguMTA1IDIxLjIzIDI3LjUgMjIgMjcuNUwzMyAyNy41QzMzLjc3IDI3LjUgMzQuMzc1IDI4LjEwNSAzNC4zNzUgMjguODc1QzM0LjM3NSAyOS42NDUgMzMuNzcgMzAuMjUgMzMgMzAuMjVMMjIgMzAuMjVDMjEuMjMgMzAuMjUgMjAuNjI1IDI5LjY0NSAyMC42MjUgMjguODc1WiIgZmlsbD0idXJsKCNwYWludF9saW5lYXJfMCkiIGZpbGwtcnVsZT0iZXZlbm9kZCIgLz4KPC9zdmc+Cg==) 50%/contain no-repeat;display:inline-block}.NP1U9q_name{vertical-align:middle;align-items:center;min-width:0;height:24px;display:inline-flex}.NP1U9q_name:before{content:\"AI Shell\";letter-spacing:.04em;color:var(--dsw-alias-label-primary,#1a1a1a);white-space:nowrap;font-size:18px;font-weight:600;line-height:24px}";
|
|
31
32
|
const tagId = "@huaweidevtools/aishell-dsh-brand//home/eushing/opensource/aishell-dsh-plugins/packages/aishell-brand/src/client/brand.module.css";
|
|
32
33
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
33
34
|
const tag = document.createElement("style");
|
|
@@ -38,8 +39,7 @@ if (typeof document !== "undefined" && document.querySelector("style[data-plugin
|
|
|
38
39
|
}
|
|
39
40
|
var brand_module_css_default = {
|
|
40
41
|
"mark": "NP1U9q_mark",
|
|
41
|
-
"name": "NP1U9q_name"
|
|
42
|
-
"version": "NP1U9q_version"
|
|
42
|
+
"name": "NP1U9q_name"
|
|
43
43
|
};
|
|
44
44
|
|
|
45
45
|
//#endregion
|
|
@@ -109,51 +109,77 @@ const HERO_PATCH_CSS = [
|
|
|
109
109
|
" margin-top: -4px;",
|
|
110
110
|
"}"
|
|
111
111
|
].join("\n");
|
|
112
|
-
/** Inject the hero headline patch CSS
|
|
113
|
-
function
|
|
114
|
-
if (typeof
|
|
115
|
-
|
|
112
|
+
/** Inject the hero headline patch CSS; the disposer removes the tag. */
|
|
113
|
+
function installHeroPatchCss(target) {
|
|
114
|
+
if (typeof target.querySelector !== "function") return () => {};
|
|
115
|
+
if (target.querySelector("style[data-aishell-hero-patch]")) return () => {};
|
|
116
|
+
const tag = target.createElement("style");
|
|
116
117
|
tag.dataset.aishellHeroPatch = "";
|
|
117
118
|
tag.textContent = HERO_PATCH_CSS;
|
|
118
|
-
|
|
119
|
+
target.head.appendChild(tag);
|
|
120
|
+
return () => {
|
|
121
|
+
tag.remove();
|
|
122
|
+
};
|
|
119
123
|
}
|
|
120
|
-
injectHeroPatchCss();
|
|
121
124
|
/**
|
|
122
125
|
* JS hover bridge: CSS ~ only matches forward siblings, so hovering the
|
|
123
126
|
* title text cannot trigger the logo's animation (the logo sits before the
|
|
124
127
|
* title in DOM order). This adds a mouseenter/mouseleave listener on the
|
|
125
128
|
* title span that toggles a class on the logo to trigger its bob animation.
|
|
129
|
+
*
|
|
130
|
+
* The disposer removes both listeners from every span it bridged, so a reload
|
|
131
|
+
* does not stack a second pair on the same element (the `data-` marker stops a
|
|
132
|
+
* *re-install* from adding them, but it also means a later disposer cannot
|
|
133
|
+
* find them by query alone — hence the bookkeeping below).
|
|
126
134
|
*/
|
|
127
|
-
function
|
|
128
|
-
if (typeof
|
|
135
|
+
function installHeroHoverBridge(target) {
|
|
136
|
+
if (typeof target.querySelector !== "function") return () => {};
|
|
137
|
+
/** Every listener this install added, so the disposer can take them off. */
|
|
138
|
+
const bridged = [];
|
|
129
139
|
const bridge = (root) => {
|
|
130
140
|
const groups = root.querySelectorAll("[class*=\"titleGroup\"]");
|
|
131
141
|
for (const group of groups) {
|
|
132
142
|
const titleSpan = group.children[0];
|
|
133
143
|
if (!titleSpan || titleSpan.dataset.aishellHoverBridged === "true") continue;
|
|
134
144
|
titleSpan.dataset.aishellHoverBridged = "true";
|
|
135
|
-
|
|
145
|
+
const onEnter = () => {
|
|
136
146
|
const headline = titleSpan.closest("[class*=\"headline\"]");
|
|
137
147
|
const fish = headline?.querySelector("[class*=\"fish\"]");
|
|
138
148
|
fish?.classList.add("aishell-logo-hover");
|
|
139
|
-
}
|
|
140
|
-
|
|
149
|
+
};
|
|
150
|
+
const onLeave = () => {
|
|
141
151
|
const headline = titleSpan.closest("[class*=\"headline\"]");
|
|
142
152
|
const fish = headline?.querySelector("[class*=\"fish\"]");
|
|
143
153
|
fish?.classList.remove("aishell-logo-hover");
|
|
154
|
+
};
|
|
155
|
+
titleSpan.addEventListener("mouseenter", onEnter);
|
|
156
|
+
titleSpan.addEventListener("mouseleave", onLeave);
|
|
157
|
+
bridged.push({
|
|
158
|
+
element: titleSpan,
|
|
159
|
+
onEnter,
|
|
160
|
+
onLeave
|
|
144
161
|
});
|
|
145
162
|
}
|
|
146
163
|
};
|
|
147
|
-
bridge(
|
|
164
|
+
bridge(target);
|
|
148
165
|
const observer = new MutationObserver((mutations) => {
|
|
149
166
|
for (const m of mutations) for (const node of m.addedNodes) if (node.nodeType === 1) bridge(node);
|
|
150
167
|
});
|
|
151
|
-
observer.observe(
|
|
168
|
+
observer.observe(target.body, {
|
|
152
169
|
childList: true,
|
|
153
170
|
subtree: true
|
|
154
171
|
});
|
|
172
|
+
return () => {
|
|
173
|
+
observer.disconnect();
|
|
174
|
+
for (const { element, onEnter, onLeave } of bridged) {
|
|
175
|
+
element.removeEventListener("mouseenter", onEnter);
|
|
176
|
+
element.removeEventListener("mouseleave", onLeave);
|
|
177
|
+
delete element.dataset.aishellHoverBridged;
|
|
178
|
+
element.closest("[class*=\"headline\"]")?.querySelector("[class*=\"fish\"]")?.classList.remove("aishell-logo-hover");
|
|
179
|
+
}
|
|
180
|
+
bridged.length = 0;
|
|
181
|
+
};
|
|
155
182
|
}
|
|
156
|
-
bridgeHeroHover();
|
|
157
183
|
/**
|
|
158
184
|
* Render the AI Shell mark with the presentation requested by its host surface.
|
|
159
185
|
* Used in both the expanded sidebar brand row and the collapsed rail.
|
|
@@ -170,18 +196,15 @@ function AishellBrandMark({ size }) {
|
|
|
170
196
|
});
|
|
171
197
|
}
|
|
172
198
|
/**
|
|
173
|
-
* Render the AI Shell name
|
|
174
|
-
*
|
|
199
|
+
* Render the AI Shell name in the sidebar brand row. The product name itself
|
|
200
|
+
* is drawn by the CSS module's `.name::before` (content: 'AI Shell'), so the
|
|
201
|
+
* markup is a single empty span.
|
|
175
202
|
*/
|
|
176
203
|
function AishellBrandName() {
|
|
177
204
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
178
205
|
className: brand_module_css_default.name,
|
|
179
206
|
role: "img",
|
|
180
|
-
"aria-label": "AI Shell"
|
|
181
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
182
|
-
className: brand_module_css_default.version,
|
|
183
|
-
children: "0.0.3"
|
|
184
|
-
})
|
|
207
|
+
"aria-label": "AI Shell"
|
|
185
208
|
});
|
|
186
209
|
}
|
|
187
210
|
/**
|
|
@@ -203,33 +226,661 @@ function AishellHeroBrandMark({ size, className }) {
|
|
|
203
226
|
* Insert "Powered by deepseek-harness" below the hero headline, centered
|
|
204
227
|
* inside .stack. Uses a MutationObserver because the hero mounts/unmounts
|
|
205
228
|
* as the user navigates between sessions.
|
|
229
|
+
*
|
|
230
|
+
* The disposer stops the observer and removes every label this install added,
|
|
231
|
+
* so unloading the plugin leaves the hero exactly as it found it.
|
|
206
232
|
*/
|
|
207
|
-
function
|
|
208
|
-
if (typeof
|
|
233
|
+
function installPoweredBy(target) {
|
|
234
|
+
if (typeof target.querySelector !== "function") return () => {};
|
|
235
|
+
/** The labels this install inserted, for removal on dispose. */
|
|
236
|
+
const inserted = [];
|
|
209
237
|
const insert = (root) => {
|
|
210
238
|
const stacks = root.querySelectorAll("[class*=\"stack\"]");
|
|
211
239
|
for (const stack of stacks) {
|
|
212
240
|
if (!stack.querySelector("[class*=\"headline\"]")) continue;
|
|
213
241
|
if (stack.querySelector("[data-aishell-powered-by]")) continue;
|
|
214
|
-
const label =
|
|
242
|
+
const label = target.createElement("div");
|
|
215
243
|
label.dataset.aishellPoweredBy = "";
|
|
216
244
|
label.style.cssText = "text-align:center;font-size:11px;font-weight:400;line-height:16px;color:var(--dsw-alias-label-quaternary, #999);user-select:none;white-space:nowrap;";
|
|
217
245
|
label.textContent = "Powered by deepseek-harness";
|
|
218
246
|
const headline = stack.querySelector("[class*=\"headline\"]");
|
|
219
247
|
if (headline && headline.nextSibling) stack.insertBefore(label, headline.nextSibling);
|
|
220
248
|
else stack.appendChild(label);
|
|
249
|
+
inserted.push(label);
|
|
221
250
|
}
|
|
222
251
|
};
|
|
223
|
-
insert(
|
|
252
|
+
insert(target);
|
|
224
253
|
const observer = new MutationObserver((mutations) => {
|
|
225
254
|
for (const m of mutations) for (const node of m.addedNodes) if (node.nodeType === 1) insert(node);
|
|
226
255
|
});
|
|
227
|
-
observer.observe(
|
|
256
|
+
observer.observe(target.body, {
|
|
228
257
|
childList: true,
|
|
229
258
|
subtree: true
|
|
230
259
|
});
|
|
260
|
+
return () => {
|
|
261
|
+
observer.disconnect();
|
|
262
|
+
for (const label of inserted) label.remove();
|
|
263
|
+
inserted.length = 0;
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
//#endregion
|
|
268
|
+
//#region src/client/suggestions.ts
|
|
269
|
+
/**
|
|
270
|
+
* The cards, in display order.
|
|
271
|
+
*
|
|
272
|
+
* Order matters only for the ring's starting window: the strip opens on the
|
|
273
|
+
* first {@link VISIBLE} cards, so the first entries are the ones a person
|
|
274
|
+
* sees without pressing an arrow.
|
|
275
|
+
*/
|
|
276
|
+
const SUGGESTIONS = [
|
|
277
|
+
{
|
|
278
|
+
id: "inventory",
|
|
279
|
+
icon: "cloud",
|
|
280
|
+
titleKey: "suggestion.inventory.title",
|
|
281
|
+
glossKey: "suggestion.inventory.gloss",
|
|
282
|
+
promptKey: "suggestion.inventory.prompt"
|
|
283
|
+
},
|
|
284
|
+
{
|
|
285
|
+
id: "deploy",
|
|
286
|
+
icon: "deploy",
|
|
287
|
+
titleKey: "suggestion.deploy.title",
|
|
288
|
+
glossKey: "suggestion.deploy.gloss",
|
|
289
|
+
promptKey: "suggestion.deploy.prompt"
|
|
290
|
+
},
|
|
291
|
+
{
|
|
292
|
+
id: "enterprise",
|
|
293
|
+
icon: "architecture",
|
|
294
|
+
titleKey: "suggestion.enterprise.title",
|
|
295
|
+
glossKey: "suggestion.enterprise.gloss",
|
|
296
|
+
promptKey: "suggestion.enterprise.prompt"
|
|
297
|
+
},
|
|
298
|
+
{
|
|
299
|
+
id: "billing",
|
|
300
|
+
icon: "cost",
|
|
301
|
+
titleKey: "suggestion.billing.title",
|
|
302
|
+
glossKey: "suggestion.billing.gloss",
|
|
303
|
+
promptKey: "suggestion.billing.prompt"
|
|
304
|
+
}
|
|
305
|
+
];
|
|
306
|
+
|
|
307
|
+
//#endregion
|
|
308
|
+
//#region src/client/suggestion-icons.tsx
|
|
309
|
+
/** One stroked path with the shared paint attributes. */
|
|
310
|
+
function Stroke({ d }) {
|
|
311
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
|
|
312
|
+
d,
|
|
313
|
+
fill: "none",
|
|
314
|
+
stroke: "currentColor",
|
|
315
|
+
strokeWidth: "1.7",
|
|
316
|
+
strokeLinecap: "round",
|
|
317
|
+
strokeLinejoin: "round"
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
/**
|
|
321
|
+
* A stack of servers: the resource inventory.
|
|
322
|
+
*
|
|
323
|
+
* Three stacked slabs with a status dot each — unmistakably "machines you
|
|
324
|
+
* own", and it shares no silhouette with any other glyph here.
|
|
325
|
+
*/
|
|
326
|
+
function InventoryIcon() {
|
|
327
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
328
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Stroke, { d: "M4 5.5h16v4H4z" }),
|
|
329
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Stroke, { d: "M4 14.5h16v4H4z" }),
|
|
330
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Stroke, { d: "M7 7.5h.01" }),
|
|
331
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Stroke, { d: "M7 16.5h.01" })
|
|
332
|
+
] });
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* A rocket: deploying something so it runs.
|
|
336
|
+
*
|
|
337
|
+
* Chosen over any box-with-arrow because that family is exactly the share
|
|
338
|
+
* glyph. A rocket is a single closed silhouette — nothing in this set can
|
|
339
|
+
* be confused with it.
|
|
340
|
+
*/
|
|
341
|
+
function DeployIcon() {
|
|
342
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
343
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Stroke, { d: "M12 3c2.8 1.9 4.2 4.6 4.2 7.6 0 2.3-.9 4.3-2.1 5.6H9.9C8.7 14.9 7.8 12.9 7.8 10.6 7.8 7.6 9.2 4.9 12 3Z" }),
|
|
344
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Stroke, { d: "M9.9 16.2 8.4 19.4l2.3-1M14.1 16.2l1.5 3.2-2.3-1" }),
|
|
345
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Stroke, { d: "M12 9.4a1.3 1.3 0 1 0 0 2.6 1.3 1.3 0 0 0 0-2.6Z" })
|
|
346
|
+
] });
|
|
347
|
+
}
|
|
348
|
+
/**
|
|
349
|
+
* A layered sitemap: account hierarchy and network partitions.
|
|
350
|
+
*
|
|
351
|
+
* One node branching to three, drawn as a single tree — reads as "structure"
|
|
352
|
+
* rather than "file" or "folder", which a plain box-and-boxes would.
|
|
353
|
+
*/
|
|
354
|
+
function ArchitectureIcon() {
|
|
355
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
356
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Stroke, { d: "M9.5 3.5h5v3.4h-5z" }),
|
|
357
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Stroke, { d: "M3.5 17.1h5v3.4h-5z" }),
|
|
358
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Stroke, { d: "M9.5 17.1h5v3.4h-5z" }),
|
|
359
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Stroke, { d: "M15.5 17.1h5v3.4h-5z" }),
|
|
360
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Stroke, { d: "M12 6.9v4.2" }),
|
|
361
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Stroke, { d: "M6 17.1v-2.4h12v2.4" })
|
|
362
|
+
] });
|
|
363
|
+
}
|
|
364
|
+
/**
|
|
365
|
+
* A receipt with a downward trend: cost review.
|
|
366
|
+
*
|
|
367
|
+
* The torn bottom edge is what makes it a bill rather than a document —
|
|
368
|
+
* without it the shape is a generic page and reads as "export a report".
|
|
369
|
+
*/
|
|
370
|
+
function CostIcon() {
|
|
371
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
372
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Stroke, { d: "M6 3.5h12v17l-2-1.4-2 1.4-2-1.4-2 1.4-2-1.4-2 1.4z" }),
|
|
373
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Stroke, { d: "M9.5 8.4h5" }),
|
|
374
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Stroke, { d: "M9.5 12.2h3.2" })
|
|
375
|
+
] });
|
|
376
|
+
}
|
|
377
|
+
/** Resolve one icon key to its glyph. */
|
|
378
|
+
function SuggestionIconArt({ icon, size = 20 }) {
|
|
379
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
|
|
380
|
+
"aria-hidden": true,
|
|
381
|
+
width: size,
|
|
382
|
+
height: size,
|
|
383
|
+
viewBox: "0 0 24 24",
|
|
384
|
+
style: { flex: "none" },
|
|
385
|
+
children: [
|
|
386
|
+
icon === "cloud" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InventoryIcon, {}),
|
|
387
|
+
icon === "deploy" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DeployIcon, {}),
|
|
388
|
+
icon === "architecture" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ArchitectureIcon, {}),
|
|
389
|
+
icon === "cost" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CostIcon, {})
|
|
390
|
+
]
|
|
391
|
+
});
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
//#endregion
|
|
395
|
+
//#region src/client/carousel.ts
|
|
396
|
+
/**
|
|
397
|
+
* Carousel position maths, kept pure so it can be tested without a DOM.
|
|
398
|
+
*
|
|
399
|
+
* The strip is a RING, not a scroll range: the cards form a circle, and an
|
|
400
|
+
* arrow steps one card around it forever. Clicking next from the last
|
|
401
|
+
* position lands on the first, and clicking prev from the first lands on the
|
|
402
|
+
* last — and crucially, every intermediate position exists. A four-card ring
|
|
403
|
+
* showing three at a time has FOUR positions, not two:
|
|
404
|
+
*
|
|
405
|
+
* cards 1 2 3 4, three visible
|
|
406
|
+
* pos 0 → [1 2 3]
|
|
407
|
+
* pos 1 → [2 3 4]
|
|
408
|
+
* pos 2 → [3 4 1] ← the wrap is visible, not a jump back
|
|
409
|
+
* pos 3 → [4 1 2]
|
|
410
|
+
* pos 4 → [1 2 3] same as pos 0
|
|
411
|
+
*
|
|
412
|
+
* A plain scroll container cannot express that: its range is only
|
|
413
|
+
* `content - viewport` (one step, for four cards), and positions 2 and 3 have
|
|
414
|
+
* no place to live. So the card list is rendered {@link COPIES} times over
|
|
415
|
+
* and the window travels through the middle copy, where both neighbours
|
|
416
|
+
* always have content.
|
|
417
|
+
*
|
|
418
|
+
* ## Why the copies, and how the seam stays invisible
|
|
419
|
+
*
|
|
420
|
+
* With the list rendered three times, a window at physical position `p` shows
|
|
421
|
+
* `cards[p .. p+VISIBLE-1]`, and position `2n` shows exactly what position `n`
|
|
422
|
+
* shows. That equivalence is the seam: once a slide settles at `2n`, the
|
|
423
|
+
* track can be placed at `n` in the same frame with transitions off, and
|
|
424
|
+
* nothing on screen changes. The same holds at the other end, where `n-1` and
|
|
425
|
+
* `2n-1` are the same window.
|
|
426
|
+
*
|
|
427
|
+
* The rewind happens only AFTER the slide finishes — never before. Jumping
|
|
428
|
+
* first would put the destination on screen instantly and then animate away
|
|
429
|
+
* from it, so a click at the seam would appear to skip a card. This is the
|
|
430
|
+
* one law in this module that a reader is likely to get backwards.
|
|
431
|
+
*
|
|
432
|
+
* @module @huaweidevtools/aishell-dsh-brand/client/carousel
|
|
433
|
+
*/
|
|
434
|
+
/**
|
|
435
|
+
* How many times the card list is rendered.
|
|
436
|
+
*
|
|
437
|
+
* Three is the minimum that works. The window lives in the middle copy, so it
|
|
438
|
+
* needs one full copy behind it (to show the cards before the start) and one
|
|
439
|
+
* ahead (to show the cards past the end while a slide is finishing at the
|
|
440
|
+
* seam, where the position may briefly reach `2n` and read up to
|
|
441
|
+
* `2n + VISIBLE - 1`).
|
|
442
|
+
*/
|
|
443
|
+
const COPIES = 3;
|
|
444
|
+
/** How many cards to render for a ring of `n`. */
|
|
445
|
+
function ringLength(n) {
|
|
446
|
+
return n * COPIES;
|
|
447
|
+
}
|
|
448
|
+
/**
|
|
449
|
+
* The physical position the ring starts at — the first card of the middle
|
|
450
|
+
* copy. Starting here rather than at 0 is what makes the very first prev
|
|
451
|
+
* click land on a real card instead of an empty track.
|
|
452
|
+
*/
|
|
453
|
+
function ringStart(n) {
|
|
454
|
+
return n;
|
|
455
|
+
}
|
|
456
|
+
/**
|
|
457
|
+
* Where a settled position should be silently rewound to, or `null` when it
|
|
458
|
+
* is already inside the working band.
|
|
459
|
+
*
|
|
460
|
+
* The band is `[n, 2n-1]`. A slide may finish one past either end — `2n`
|
|
461
|
+
* going forward, `n-1` going backward — and both have an exact twin inside
|
|
462
|
+
* the band. See the module note for why this runs after the slide, not
|
|
463
|
+
* before.
|
|
464
|
+
*/
|
|
465
|
+
function rewindTo(pos, n) {
|
|
466
|
+
if (pos >= 2 * n) return n;
|
|
467
|
+
if (pos < n) return 2 * n - 1;
|
|
468
|
+
return null;
|
|
469
|
+
}
|
|
470
|
+
/**
|
|
471
|
+
* Resolve one arrow press on a ring.
|
|
472
|
+
*
|
|
473
|
+
* Any rewind still owed from the previous press is settled first, so a person
|
|
474
|
+
* clicking faster than the slide animation cannot walk the window off the
|
|
475
|
+
* rendered copies — the band always absorbs one more step.
|
|
476
|
+
*/
|
|
477
|
+
function ringStep(pos, delta, n) {
|
|
478
|
+
const owed = rewindTo(pos, n);
|
|
479
|
+
const from = owed ?? pos;
|
|
480
|
+
return {
|
|
481
|
+
from,
|
|
482
|
+
to: from + delta
|
|
483
|
+
};
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
//#endregion
|
|
487
|
+
//#region src/client/SuggestionCards.tsx
|
|
488
|
+
/** How many cards a full-width strip shows at once. */
|
|
489
|
+
const VISIBLE = 3;
|
|
490
|
+
/** One card. */
|
|
491
|
+
function Card({ suggestion, onPick, t }) {
|
|
492
|
+
const [hover, setHover] = (0, react.useState)(false);
|
|
493
|
+
const [focus, setFocus] = (0, react.useState)(false);
|
|
494
|
+
const lit = hover || focus;
|
|
495
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
496
|
+
type: "button",
|
|
497
|
+
onClick: () => {
|
|
498
|
+
onPick(t(suggestion.promptKey));
|
|
499
|
+
},
|
|
500
|
+
onPointerEnter: () => {
|
|
501
|
+
setHover(true);
|
|
502
|
+
},
|
|
503
|
+
onPointerLeave: () => {
|
|
504
|
+
setHover(false);
|
|
505
|
+
},
|
|
506
|
+
onFocus: () => {
|
|
507
|
+
setFocus(true);
|
|
508
|
+
},
|
|
509
|
+
onBlur: () => {
|
|
510
|
+
setFocus(false);
|
|
511
|
+
},
|
|
512
|
+
style: {
|
|
513
|
+
flex: `0 0 calc((100cqw - ${VISIBLE - 1} * var(--dsh-suggestion-gap)) / ${VISIBLE})`,
|
|
514
|
+
display: "flex",
|
|
515
|
+
alignItems: "flex-start",
|
|
516
|
+
gap: 10,
|
|
517
|
+
boxSizing: "border-box",
|
|
518
|
+
minWidth: 0,
|
|
519
|
+
padding: "12px 14px",
|
|
520
|
+
textAlign: "left",
|
|
521
|
+
font: "inherit",
|
|
522
|
+
cursor: "pointer",
|
|
523
|
+
color: "var(--dsw-alias-label-primary)",
|
|
524
|
+
background: lit ? "var(--dsw-alias-interactive-bg-hover)" : "var(--dsw-alias-bg-module-platform)",
|
|
525
|
+
border: `1px solid ${lit ? "var(--dsw-alias-border-l2)" : "var(--dsw-alias-border-l3)"}`,
|
|
526
|
+
borderRadius: 10,
|
|
527
|
+
transition: "background 120ms ease, border-color 120ms ease",
|
|
528
|
+
outline: focus ? "2px solid var(--dsw-alias-state-business-primary)" : "none",
|
|
529
|
+
outlineOffset: 2
|
|
530
|
+
},
|
|
531
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
532
|
+
style: {
|
|
533
|
+
color: "var(--dsw-alias-label-secondary)",
|
|
534
|
+
marginTop: 1
|
|
535
|
+
},
|
|
536
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SuggestionIconArt, { icon: suggestion.icon })
|
|
537
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
538
|
+
style: {
|
|
539
|
+
display: "flex",
|
|
540
|
+
flexDirection: "column",
|
|
541
|
+
gap: 2,
|
|
542
|
+
minWidth: 0
|
|
543
|
+
},
|
|
544
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
545
|
+
style: {
|
|
546
|
+
fontSize: "var(--dsh-content-font-size-secondary, 13px)",
|
|
547
|
+
fontWeight: 500,
|
|
548
|
+
lineHeight: "20px",
|
|
549
|
+
overflow: "hidden",
|
|
550
|
+
textOverflow: "ellipsis",
|
|
551
|
+
whiteSpace: "nowrap"
|
|
552
|
+
},
|
|
553
|
+
children: t(suggestion.titleKey)
|
|
554
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
555
|
+
style: {
|
|
556
|
+
fontSize: "12px",
|
|
557
|
+
lineHeight: "16px",
|
|
558
|
+
color: "var(--dsw-alias-label-tertiary)",
|
|
559
|
+
display: "-webkit-box",
|
|
560
|
+
WebkitLineClamp: 2,
|
|
561
|
+
WebkitBoxOrient: "vertical",
|
|
562
|
+
overflow: "hidden"
|
|
563
|
+
},
|
|
564
|
+
children: t(suggestion.glossKey)
|
|
565
|
+
})]
|
|
566
|
+
})]
|
|
567
|
+
});
|
|
568
|
+
}
|
|
569
|
+
/** One carousel arrow. */
|
|
570
|
+
function Arrow({ direction, label, onClick }) {
|
|
571
|
+
const [hover, setHover] = (0, react.useState)(false);
|
|
572
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
573
|
+
type: "button",
|
|
574
|
+
"aria-label": label,
|
|
575
|
+
onClick,
|
|
576
|
+
onPointerEnter: () => {
|
|
577
|
+
setHover(true);
|
|
578
|
+
},
|
|
579
|
+
onPointerLeave: () => {
|
|
580
|
+
setHover(false);
|
|
581
|
+
},
|
|
582
|
+
style: {
|
|
583
|
+
flex: "none",
|
|
584
|
+
display: "inline-flex",
|
|
585
|
+
alignItems: "center",
|
|
586
|
+
justifyContent: "center",
|
|
587
|
+
width: 26,
|
|
588
|
+
height: 26,
|
|
589
|
+
padding: 0,
|
|
590
|
+
cursor: "pointer",
|
|
591
|
+
color: "var(--dsw-alias-label-secondary)",
|
|
592
|
+
background: hover ? "var(--dsw-alias-interactive-bg-hover)" : "transparent",
|
|
593
|
+
border: "none",
|
|
594
|
+
borderRadius: 999,
|
|
595
|
+
transition: "background 120ms ease"
|
|
596
|
+
},
|
|
597
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
|
|
598
|
+
"aria-hidden": true,
|
|
599
|
+
width: "14",
|
|
600
|
+
height: "14",
|
|
601
|
+
viewBox: "0 0 24 24",
|
|
602
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
|
|
603
|
+
d: direction === "prev" ? "M15 5l-7 7 7 7" : "M9 5l7 7-7 7",
|
|
604
|
+
fill: "none",
|
|
605
|
+
stroke: "currentColor",
|
|
606
|
+
strokeWidth: "2",
|
|
607
|
+
strokeLinecap: "round",
|
|
608
|
+
strokeLinejoin: "round"
|
|
609
|
+
})
|
|
610
|
+
})
|
|
611
|
+
});
|
|
612
|
+
}
|
|
613
|
+
function SuggestionCards(props) {
|
|
614
|
+
const blank = props.useSession((session) => session.blank);
|
|
615
|
+
const setDraft = props.inputActions.setDraft;
|
|
616
|
+
const t = props.t;
|
|
617
|
+
const n = SUGGESTIONS.length;
|
|
618
|
+
const ring = n > VISIBLE;
|
|
619
|
+
const viewportRef = (0, react.useRef)(null);
|
|
620
|
+
const trackRef = (0, react.useRef)(null);
|
|
621
|
+
const posRef = (0, react.useRef)(ringStart(n));
|
|
622
|
+
const stepRef = (0, react.useRef)(0);
|
|
623
|
+
const [animating, setAnimating] = (0, react.useState)(true);
|
|
624
|
+
const [ready, setReady] = (0, react.useState)(!ring);
|
|
625
|
+
/** Place the track at a position with no transition. */
|
|
626
|
+
const snapTo = (0, react.useCallback)((pos) => {
|
|
627
|
+
const track = trackRef.current;
|
|
628
|
+
if (track === null) return;
|
|
629
|
+
track.style.transition = "none";
|
|
630
|
+
track.style.transform = `translate3d(${-pos * stepRef.current}px, 0, 0)`;
|
|
631
|
+
}, []);
|
|
632
|
+
/** Animate the track to a position. */
|
|
633
|
+
const slideTo = (0, react.useCallback)((pos) => {
|
|
634
|
+
const track = trackRef.current;
|
|
635
|
+
if (track === null) return;
|
|
636
|
+
track.style.transition = "";
|
|
637
|
+
track.style.transform = `translate3d(${-pos * stepRef.current}px, 0, 0)`;
|
|
638
|
+
}, []);
|
|
639
|
+
/**
|
|
640
|
+
* Measure one step, then place the ring at its start.
|
|
641
|
+
*
|
|
642
|
+
* The step is read from a real card rather than computed from the viewport
|
|
643
|
+
* width so the fraction in `Card`'s flex-basis and this number cannot drift
|
|
644
|
+
* apart, and so a breakpoint change needs no constant updated here.
|
|
645
|
+
*/
|
|
646
|
+
/**
|
|
647
|
+
* Re-measure one step and re-apply the current position.
|
|
648
|
+
*
|
|
649
|
+
* The step is read from a real card rather than computed from the viewport
|
|
650
|
+
* width so the `cqw` fraction in `Card`'s flex-basis and this number cannot
|
|
651
|
+
* drift apart.
|
|
652
|
+
*
|
|
653
|
+
* Re-measuring is not optional. The first frame measures BEFORE the cards
|
|
654
|
+
* have their final width: `containerType` and the `cqw` basis settle in a
|
|
655
|
+
* later layout pass, so the first reading is a few percent too large (242px
|
|
656
|
+
* where the settled card is 213px). A step kept from that frame puts every
|
|
657
|
+
* position slightly too far along, which compounds — by the fourth card the
|
|
658
|
+
* window has drifted a whole card and shows two cards plus a gap.
|
|
659
|
+
*/
|
|
660
|
+
const remeasure = (0, react.useCallback)(() => {
|
|
661
|
+
const track = trackRef.current;
|
|
662
|
+
if (track === null) return false;
|
|
663
|
+
const first = track.firstElementChild;
|
|
664
|
+
if (first === null) return false;
|
|
665
|
+
const gap = Number.parseFloat(getComputedStyle(track).columnGap) || 0;
|
|
666
|
+
const step$1 = first.getBoundingClientRect().width + gap;
|
|
667
|
+
if (!(step$1 > 0)) return false;
|
|
668
|
+
const changed = step$1 !== stepRef.current;
|
|
669
|
+
stepRef.current = step$1;
|
|
670
|
+
if (changed) {
|
|
671
|
+
setAnimating(false);
|
|
672
|
+
snapTo(posRef.current);
|
|
673
|
+
window.requestAnimationFrame(() => {
|
|
674
|
+
setAnimating(true);
|
|
675
|
+
});
|
|
676
|
+
}
|
|
677
|
+
return true;
|
|
678
|
+
}, [snapTo]);
|
|
679
|
+
(0, react.useEffect)(() => {
|
|
680
|
+
if (!blank || !ring) return;
|
|
681
|
+
let cancelled = false;
|
|
682
|
+
const settle = () => {
|
|
683
|
+
if (cancelled) return;
|
|
684
|
+
if (!remeasure()) {
|
|
685
|
+
frame = window.requestAnimationFrame(settle);
|
|
686
|
+
return;
|
|
687
|
+
}
|
|
688
|
+
posRef.current = ringStart(n);
|
|
689
|
+
setAnimating(false);
|
|
690
|
+
snapTo(posRef.current);
|
|
691
|
+
window.requestAnimationFrame(() => {
|
|
692
|
+
if (cancelled) return;
|
|
693
|
+
setAnimating(true);
|
|
694
|
+
setReady(true);
|
|
695
|
+
const viewport = viewportRef.current;
|
|
696
|
+
if (viewport !== null) {
|
|
697
|
+
observer = new ResizeObserver(() => {
|
|
698
|
+
remeasure();
|
|
699
|
+
});
|
|
700
|
+
observer.observe(viewport);
|
|
701
|
+
}
|
|
702
|
+
});
|
|
703
|
+
};
|
|
704
|
+
let frame = window.requestAnimationFrame(settle);
|
|
705
|
+
let observer;
|
|
706
|
+
return () => {
|
|
707
|
+
cancelled = true;
|
|
708
|
+
window.cancelAnimationFrame(frame);
|
|
709
|
+
observer?.disconnect();
|
|
710
|
+
};
|
|
711
|
+
}, [
|
|
712
|
+
blank,
|
|
713
|
+
ring,
|
|
714
|
+
n,
|
|
715
|
+
remeasure,
|
|
716
|
+
snapTo
|
|
717
|
+
]);
|
|
718
|
+
/**
|
|
719
|
+
* Apply whichever rewind the settling position owes, then re-arm the
|
|
720
|
+
* transition.
|
|
721
|
+
*
|
|
722
|
+
* Runs on `transitionend`, never before the slide: jumping to the twin
|
|
723
|
+
* position first would put the destination on screen immediately and then
|
|
724
|
+
* animate away from it, so a click at the seam would look like it skipped
|
|
725
|
+
* a card. See the module note in carousel.ts.
|
|
726
|
+
*/
|
|
727
|
+
const onSettle = (0, react.useCallback)(() => {
|
|
728
|
+
if (!ring) return;
|
|
729
|
+
const owed = rewindTo(posRef.current, n);
|
|
730
|
+
if (owed === null) return;
|
|
731
|
+
posRef.current = owed;
|
|
732
|
+
setAnimating(false);
|
|
733
|
+
snapTo(owed);
|
|
734
|
+
window.requestAnimationFrame(() => {
|
|
735
|
+
setAnimating(true);
|
|
736
|
+
});
|
|
737
|
+
}, [
|
|
738
|
+
ring,
|
|
739
|
+
n,
|
|
740
|
+
snapTo
|
|
741
|
+
]);
|
|
742
|
+
/** One arrow press. */
|
|
743
|
+
const step = (0, react.useCallback)((delta) => {
|
|
744
|
+
if (!ring || !ready) return;
|
|
745
|
+
const { from, to } = ringStep(posRef.current, delta, n);
|
|
746
|
+
if (from !== posRef.current) {
|
|
747
|
+
posRef.current = from;
|
|
748
|
+
setAnimating(false);
|
|
749
|
+
snapTo(from);
|
|
750
|
+
}
|
|
751
|
+
posRef.current = to;
|
|
752
|
+
window.requestAnimationFrame(() => {
|
|
753
|
+
setAnimating(true);
|
|
754
|
+
slideTo(to);
|
|
755
|
+
});
|
|
756
|
+
}, [
|
|
757
|
+
ring,
|
|
758
|
+
ready,
|
|
759
|
+
n,
|
|
760
|
+
snapTo,
|
|
761
|
+
slideTo
|
|
762
|
+
]);
|
|
763
|
+
if (!blank) return null;
|
|
764
|
+
if (n === 0) return null;
|
|
765
|
+
const cards = ring ? Array.from({ length: ringLength(n) }, (_, i) => SUGGESTIONS[i % n]) : SUGGESTIONS;
|
|
766
|
+
const strip = /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
767
|
+
ref: viewportRef,
|
|
768
|
+
"data-aishell-suggestions": n,
|
|
769
|
+
style: {
|
|
770
|
+
overflow: "hidden",
|
|
771
|
+
minWidth: 0,
|
|
772
|
+
flex: "1 1 auto",
|
|
773
|
+
containerType: "inline-size"
|
|
774
|
+
},
|
|
775
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
776
|
+
ref: trackRef,
|
|
777
|
+
"data-aishell-suggestion-track": ring ? "ring" : "flat",
|
|
778
|
+
onTransitionEnd: onSettle,
|
|
779
|
+
style: {
|
|
780
|
+
display: "flex",
|
|
781
|
+
alignItems: "stretch",
|
|
782
|
+
gap: "var(--dsh-suggestion-gap)",
|
|
783
|
+
width: "max-content",
|
|
784
|
+
willChange: "transform",
|
|
785
|
+
transition: animating ? "transform 320ms cubic-bezier(.22,.61,.36,1)" : "none",
|
|
786
|
+
transform: "translate3d(0, 0, 0)"
|
|
787
|
+
},
|
|
788
|
+
children: cards.map((suggestion, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Card, {
|
|
789
|
+
suggestion,
|
|
790
|
+
onPick: setDraft,
|
|
791
|
+
t
|
|
792
|
+
}, `${i}:${suggestion.id}`))
|
|
793
|
+
})
|
|
794
|
+
});
|
|
795
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
796
|
+
style: {
|
|
797
|
+
["--dsh-suggestion-gap"]: "8px",
|
|
798
|
+
display: "flex",
|
|
799
|
+
alignItems: "center",
|
|
800
|
+
gap: 6,
|
|
801
|
+
minWidth: 0,
|
|
802
|
+
margin: "4px 0 8px"
|
|
803
|
+
},
|
|
804
|
+
children: [
|
|
805
|
+
ring && ready && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Arrow, {
|
|
806
|
+
direction: "prev",
|
|
807
|
+
label: t("suggestion.previous"),
|
|
808
|
+
onClick: () => {
|
|
809
|
+
step(-1);
|
|
810
|
+
}
|
|
811
|
+
}),
|
|
812
|
+
strip,
|
|
813
|
+
ring && ready && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Arrow, {
|
|
814
|
+
direction: "next",
|
|
815
|
+
label: t("suggestion.next"),
|
|
816
|
+
onClick: () => {
|
|
817
|
+
step(1);
|
|
818
|
+
}
|
|
819
|
+
})
|
|
820
|
+
]
|
|
821
|
+
});
|
|
231
822
|
}
|
|
232
|
-
|
|
823
|
+
|
|
824
|
+
//#endregion
|
|
825
|
+
//#region src/client/locales.ts
|
|
826
|
+
/**
|
|
827
|
+
* aishell brand locale dictionaries.
|
|
828
|
+
*
|
|
829
|
+
* The brand plugin owns its own namespace rather than reusing `aishell`
|
|
830
|
+
* (which `aishell-credentials` registers): a namespace's texts have exactly
|
|
831
|
+
* one owner, and a duplicate `(ns, locale)` registration throws.
|
|
832
|
+
*
|
|
833
|
+
* ## Why content lives in a dictionary
|
|
834
|
+
*
|
|
835
|
+
* The suggestion cards are the only strings in this plugin a person reads,
|
|
836
|
+
* and they are CONTENT rather than interface chrome — a card title, its
|
|
837
|
+
* one-line gloss, and the prompt a click inserts. They still belong here:
|
|
838
|
+
* a card that says「云资源查询」to an English reader is worse than no card,
|
|
839
|
+
* and the prompt it inserts would start an English conversation in Chinese.
|
|
840
|
+
*
|
|
841
|
+
* Chinese is the key-set source of truth; English is complete against it and
|
|
842
|
+
* is also the terminal fallback, so every locale other than `zh` reads
|
|
843
|
+
* English. That is the framework's own chain (`LOCALE_IDS = ["zh", "en"]`,
|
|
844
|
+
* with English carrying no fallback) — there is no third dictionary to write.
|
|
845
|
+
*
|
|
846
|
+
* @module @huaweidevtools/aishell-dsh-brand/client/locales
|
|
847
|
+
*/
|
|
848
|
+
/** Dictionary namespace owned by this plugin. */
|
|
849
|
+
const NS = "aishell-brand";
|
|
850
|
+
/** Simplified Chinese dictionary (the key-set source of truth). */
|
|
851
|
+
const zh = {
|
|
852
|
+
"suggestion.previous": "上一个示例",
|
|
853
|
+
"suggestion.next": "下一个示例",
|
|
854
|
+
"suggestion.inventory.title": "云资源查询",
|
|
855
|
+
"suggestion.inventory.gloss": "列出当前账号下的云资源",
|
|
856
|
+
"suggestion.inventory.prompt": "请列出我的华为云资源清单,按服务分类(计算、存储、网络、数据库等),标出每类资源的数量和所在区域。",
|
|
857
|
+
"suggestion.deploy.title": "部署方案推荐",
|
|
858
|
+
"suggestion.deploy.gloss": "按访问量和预算给出可落地的部署路径",
|
|
859
|
+
"suggestion.deploy.prompt": "我要部署一个轻量级 Web 应用,请对比几种可行的部署方案,说明各自的适用规模、月度成本量级和运维复杂度,并给出你的推荐及理由。",
|
|
860
|
+
"suggestion.enterprise.title": "企业上云",
|
|
861
|
+
"suggestion.enterprise.gloss": "多账号、网络分区与权限边界的整体设计",
|
|
862
|
+
"suggestion.enterprise.prompt": "请为我规划一套云上 Landing Zone 架构,覆盖账号组织结构、网络分区、权限边界与审计要求,并说明各部分的设计取舍。",
|
|
863
|
+
"suggestion.billing.title": "账单分析",
|
|
864
|
+
"suggestion.billing.gloss": "分析上个月的云资源支出",
|
|
865
|
+
"suggestion.billing.prompt": "请分析我上个月的云资源支出构成,找出占比最高的几项服务,指出其中可以优化或降配的部分,并估算调整后能节省多少。"
|
|
866
|
+
};
|
|
867
|
+
/** English dictionary. Complete against {@link zh}; also the terminal fallback. */
|
|
868
|
+
const en = {
|
|
869
|
+
"suggestion.previous": "Previous example",
|
|
870
|
+
"suggestion.next": "Next example",
|
|
871
|
+
"suggestion.inventory.title": "Cloud inventory",
|
|
872
|
+
"suggestion.inventory.gloss": "List the resources in this account",
|
|
873
|
+
"suggestion.inventory.prompt": "List the resources in my Huawei Cloud account, grouped by service (compute, storage, network, database), with the count and the region for each group.",
|
|
874
|
+
"suggestion.deploy.title": "Deployment options",
|
|
875
|
+
"suggestion.deploy.gloss": "A workable path for your traffic and budget",
|
|
876
|
+
"suggestion.deploy.prompt": "I want to deploy a lightweight web application. Compare a few viable deployment options, covering the scale each one suits, its order-of-magnitude monthly cost, and its operational complexity, then recommend one and explain why.",
|
|
877
|
+
"suggestion.enterprise.title": "Landing zone",
|
|
878
|
+
"suggestion.enterprise.gloss": "Multi-account structure, network and permission boundaries",
|
|
879
|
+
"suggestion.enterprise.prompt": "Design a cloud landing zone for my organisation, covering the account structure, network partitions, permission boundaries and audit requirements, and explain the trade-offs behind each part.",
|
|
880
|
+
"suggestion.billing.title": "Billing analysis",
|
|
881
|
+
"suggestion.billing.gloss": "Break down last month's cloud spend",
|
|
882
|
+
"suggestion.billing.prompt": "Analyse my cloud spend for last month, identify the services that account for the largest share, point out what could be optimised or downsized, and estimate how much that would save."
|
|
883
|
+
};
|
|
233
884
|
|
|
234
885
|
//#endregion
|
|
235
886
|
//#region src/client/title-shadow.ts
|
|
@@ -651,9 +1302,13 @@ function unbrand(value) {
|
|
|
651
1302
|
|
|
652
1303
|
//#endregion
|
|
653
1304
|
//#region src/client/index.ts
|
|
654
|
-
/** Required
|
|
655
|
-
const inject = ["slots"];
|
|
1305
|
+
/** Required services: the UI slot registry and the locale registry. */
|
|
1306
|
+
const inject = ["slots", "locale"];
|
|
656
1307
|
function apply(ctx) {
|
|
1308
|
+
ctx.effect(() => ctx.locale.register(NS, {
|
|
1309
|
+
zh,
|
|
1310
|
+
en
|
|
1311
|
+
}), "aishell-brand: dictionaries");
|
|
657
1312
|
ctx.slots.inject("sidebar.brand.mark", () => ctx.slots.register({
|
|
658
1313
|
name: "sidebar.brand.mark",
|
|
659
1314
|
priority: -1
|
|
@@ -666,7 +1321,16 @@ function apply(ctx) {
|
|
|
666
1321
|
name: "conversation.hero.brand.mark",
|
|
667
1322
|
priority: -1
|
|
668
1323
|
}, AishellHeroBrandMark));
|
|
1324
|
+
ctx.slots.inject("conversation.input.dock", () => ctx.slots.register({
|
|
1325
|
+
name: "conversation.input.dock",
|
|
1326
|
+
id: "aishell-suggestions",
|
|
1327
|
+
order: 20,
|
|
1328
|
+
locale: NS
|
|
1329
|
+
}, SuggestionCards));
|
|
669
1330
|
if (typeof document !== "undefined") {
|
|
1331
|
+
ctx.effect(() => installHeroPatchCss(document), "aishell-brand: hero patch css");
|
|
1332
|
+
ctx.effect(() => installHeroHoverBridge(document), "aishell-brand: hero hover bridge");
|
|
1333
|
+
ctx.effect(() => installPoweredBy(document), "aishell-brand: powered-by label");
|
|
670
1334
|
ctx.effect(() => installTitleShadow(document), "aishell-brand: window title shadow");
|
|
671
1335
|
ctx.effect(() => installFaviconShadow(document), "aishell-brand: favicon shadow");
|
|
672
1336
|
ctx.effect(() => installRunningMarkShadow(document), "aishell-brand: running mark shadow");
|
|
@@ -7,14 +7,42 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import type { SidebarBrandMarkOwnerProps } from '@deepseek-ai/dsh-client-ui-sidebar/client';
|
|
9
9
|
import type { HeroBrandMarkOwnerProps } from '@deepseek-ai/dsh-client-ui-conversation/client';
|
|
10
|
+
/**
|
|
11
|
+
* A disposer undoing one module-level installation.
|
|
12
|
+
*
|
|
13
|
+
* The three helpers below all reach outside React — a `<style>` tag, event
|
|
14
|
+
* listeners, inserted nodes — so none of them is unwound by unmounting a
|
|
15
|
+
* component. They are installed through `ctx.effect` in `index.ts`, which runs
|
|
16
|
+
* the returned disposer on plugin unload. That matters beyond tidiness: the
|
|
17
|
+
* client loader tears a module down with `tearDownEntryFiber` (fiber effects)
|
|
18
|
+
* and `removeOwnedStyles` (only `style[data-plugin]` tags), so a bare
|
|
19
|
+
* `MutationObserver` on `document.body` is reachable by neither and would
|
|
20
|
+
* survive every HMR reload, accumulating one per reload.
|
|
21
|
+
*/
|
|
22
|
+
export type BrandDisposer = () => void;
|
|
23
|
+
/** Inject the hero headline patch CSS; the disposer removes the tag. */
|
|
24
|
+
export declare function installHeroPatchCss(target: Document): BrandDisposer;
|
|
25
|
+
/**
|
|
26
|
+
* JS hover bridge: CSS ~ only matches forward siblings, so hovering the
|
|
27
|
+
* title text cannot trigger the logo's animation (the logo sits before the
|
|
28
|
+
* title in DOM order). This adds a mouseenter/mouseleave listener on the
|
|
29
|
+
* title span that toggles a class on the logo to trigger its bob animation.
|
|
30
|
+
*
|
|
31
|
+
* The disposer removes both listeners from every span it bridged, so a reload
|
|
32
|
+
* does not stack a second pair on the same element (the `data-` marker stops a
|
|
33
|
+
* *re-install* from adding them, but it also means a later disposer cannot
|
|
34
|
+
* find them by query alone — hence the bookkeeping below).
|
|
35
|
+
*/
|
|
36
|
+
export declare function installHeroHoverBridge(target: Document): BrandDisposer;
|
|
10
37
|
/**
|
|
11
38
|
* Render the AI Shell mark with the presentation requested by its host surface.
|
|
12
39
|
* Used in both the expanded sidebar brand row and the collapsed rail.
|
|
13
40
|
*/
|
|
14
41
|
export declare function AishellBrandMark({ size }: SidebarBrandMarkOwnerProps): import("react").JSX.Element;
|
|
15
42
|
/**
|
|
16
|
-
* Render the AI Shell name
|
|
17
|
-
*
|
|
43
|
+
* Render the AI Shell name in the sidebar brand row. The product name itself
|
|
44
|
+
* is drawn by the CSS module's `.name::before` (content: 'AI Shell'), so the
|
|
45
|
+
* markup is a single empty span.
|
|
18
46
|
*/
|
|
19
47
|
export declare function AishellBrandName(): import("react").JSX.Element;
|
|
20
48
|
/**
|
|
@@ -22,4 +50,13 @@ export declare function AishellBrandName(): import("react").JSX.Element;
|
|
|
22
50
|
* className for surrounding mark geometry (e.g. centering).
|
|
23
51
|
*/
|
|
24
52
|
export declare function AishellHeroBrandMark({ size, className }: HeroBrandMarkOwnerProps): import("react").JSX.Element;
|
|
53
|
+
/**
|
|
54
|
+
* Insert "Powered by deepseek-harness" below the hero headline, centered
|
|
55
|
+
* inside .stack. Uses a MutationObserver because the hero mounts/unmounts
|
|
56
|
+
* as the user navigates between sessions.
|
|
57
|
+
*
|
|
58
|
+
* The disposer stops the observer and removes every label this install added,
|
|
59
|
+
* so unloading the plugin leaves the hero exactly as it found it.
|
|
60
|
+
*/
|
|
61
|
+
export declare function installPoweredBy(target: Document): BrandDisposer;
|
|
25
62
|
//# sourceMappingURL=Brand.d.ts.map
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Example-prompt cards for the New-Session hero.
|
|
3
|
+
*
|
|
4
|
+
* ## Where this renders, and why there
|
|
5
|
+
*
|
|
6
|
+
* `conversation.input.dock` is the band between the hero workspace row and
|
|
7
|
+
* the input card. It is a `list` slot, so this entry composes beside
|
|
8
|
+
* whatever else occupies the band instead of competing for a seat — the
|
|
9
|
+
* hero row's own seats (`conversation.hero.workspace`,
|
|
10
|
+
* `conversation.hero.agentPreset`) are `single` and already held by official
|
|
11
|
+
* occupants, which is the trap the account chip next door documents.
|
|
12
|
+
*
|
|
13
|
+
* ## When it renders
|
|
14
|
+
*
|
|
15
|
+
* The band itself renders in both the New-Session hero and the docked
|
|
16
|
+
* session composer — it only needs a live input zone — so the gate is
|
|
17
|
+
* `session.blank`, the same condition the account chip uses. `blank` is true
|
|
18
|
+
* from the moment a New Session opens until the first turn is accepted:
|
|
19
|
+
* exactly the window the cards exist for. Once the first message is sent the
|
|
20
|
+
* strip renders nothing and the composer takes over.
|
|
21
|
+
*
|
|
22
|
+
* ## Carousel
|
|
23
|
+
*
|
|
24
|
+
* Three cards or fewer sit side by side with no controls — a strip with
|
|
25
|
+
* nothing to scroll should not offer scrolling. More than three become a
|
|
26
|
+
* carousel: the row scrolls horizontally, arrows step it one card at a
|
|
27
|
+
* time, and it wraps at both ends. Wrapping rather than disabling the
|
|
28
|
+
* arrow at an end keeps the two controls symmetric (an arrow that is
|
|
29
|
+
* sometimes dead is a control a person has to think about), and it is what
|
|
30
|
+
* the feature was asked for.
|
|
31
|
+
*
|
|
32
|
+
* The arrows hold the scroll container's position in a ref and clamp it
|
|
33
|
+
* themselves rather than reading scrollLeft back from the DOM: the read
|
|
34
|
+
* happens before the browser has applied a pending smooth scroll, so a
|
|
35
|
+
* second click during the animation would compute from a stale position and
|
|
36
|
+
* step backwards. The container's own scroll event re-syncs the ref, so a
|
|
37
|
+
* manual trackpad scroll cannot desynchronize it.
|
|
38
|
+
*
|
|
39
|
+
* @module @huaweidevtools/aishell-dsh-brand/client/SuggestionCards
|
|
40
|
+
*/
|
|
41
|
+
import { type ReactNode } from 'react';
|
|
42
|
+
import type { PropsRuntime, PropsLocale } from '@deepseek-ai/dsh-client-ui-slots';
|
|
43
|
+
/** Full component props: the dock band's owner share + the session kit + `t`. */
|
|
44
|
+
export type SuggestionCardsProps = PropsRuntime<'conversation.input.dock'> & PropsLocale<'aishell-brand'>;
|
|
45
|
+
export declare function SuggestionCards(props: SuggestionCardsProps): ReactNode;
|
|
46
|
+
//# sourceMappingURL=SuggestionCards.d.ts.map
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Carousel position maths, kept pure so it can be tested without a DOM.
|
|
3
|
+
*
|
|
4
|
+
* The strip is a RING, not a scroll range: the cards form a circle, and an
|
|
5
|
+
* arrow steps one card around it forever. Clicking next from the last
|
|
6
|
+
* position lands on the first, and clicking prev from the first lands on the
|
|
7
|
+
* last — and crucially, every intermediate position exists. A four-card ring
|
|
8
|
+
* showing three at a time has FOUR positions, not two:
|
|
9
|
+
*
|
|
10
|
+
* cards 1 2 3 4, three visible
|
|
11
|
+
* pos 0 → [1 2 3]
|
|
12
|
+
* pos 1 → [2 3 4]
|
|
13
|
+
* pos 2 → [3 4 1] ← the wrap is visible, not a jump back
|
|
14
|
+
* pos 3 → [4 1 2]
|
|
15
|
+
* pos 4 → [1 2 3] same as pos 0
|
|
16
|
+
*
|
|
17
|
+
* A plain scroll container cannot express that: its range is only
|
|
18
|
+
* `content - viewport` (one step, for four cards), and positions 2 and 3 have
|
|
19
|
+
* no place to live. So the card list is rendered {@link COPIES} times over
|
|
20
|
+
* and the window travels through the middle copy, where both neighbours
|
|
21
|
+
* always have content.
|
|
22
|
+
*
|
|
23
|
+
* ## Why the copies, and how the seam stays invisible
|
|
24
|
+
*
|
|
25
|
+
* With the list rendered three times, a window at physical position `p` shows
|
|
26
|
+
* `cards[p .. p+VISIBLE-1]`, and position `2n` shows exactly what position `n`
|
|
27
|
+
* shows. That equivalence is the seam: once a slide settles at `2n`, the
|
|
28
|
+
* track can be placed at `n` in the same frame with transitions off, and
|
|
29
|
+
* nothing on screen changes. The same holds at the other end, where `n-1` and
|
|
30
|
+
* `2n-1` are the same window.
|
|
31
|
+
*
|
|
32
|
+
* The rewind happens only AFTER the slide finishes — never before. Jumping
|
|
33
|
+
* first would put the destination on screen instantly and then animate away
|
|
34
|
+
* from it, so a click at the seam would appear to skip a card. This is the
|
|
35
|
+
* one law in this module that a reader is likely to get backwards.
|
|
36
|
+
*
|
|
37
|
+
* @module @huaweidevtools/aishell-dsh-brand/client/carousel
|
|
38
|
+
*/
|
|
39
|
+
/**
|
|
40
|
+
* How many times the card list is rendered.
|
|
41
|
+
*
|
|
42
|
+
* Three is the minimum that works. The window lives in the middle copy, so it
|
|
43
|
+
* needs one full copy behind it (to show the cards before the start) and one
|
|
44
|
+
* ahead (to show the cards past the end while a slide is finishing at the
|
|
45
|
+
* seam, where the position may briefly reach `2n` and read up to
|
|
46
|
+
* `2n + VISIBLE - 1`).
|
|
47
|
+
*/
|
|
48
|
+
export declare const COPIES = 3;
|
|
49
|
+
/** How many cards to render for a ring of `n`. */
|
|
50
|
+
export declare function ringLength(n: number): number;
|
|
51
|
+
/**
|
|
52
|
+
* The physical position the ring starts at — the first card of the middle
|
|
53
|
+
* copy. Starting here rather than at 0 is what makes the very first prev
|
|
54
|
+
* click land on a real card instead of an empty track.
|
|
55
|
+
*/
|
|
56
|
+
export declare function ringStart(n: number): number;
|
|
57
|
+
/**
|
|
58
|
+
* Where a settled position should be silently rewound to, or `null` when it
|
|
59
|
+
* is already inside the working band.
|
|
60
|
+
*
|
|
61
|
+
* The band is `[n, 2n-1]`. A slide may finish one past either end — `2n`
|
|
62
|
+
* going forward, `n-1` going backward — and both have an exact twin inside
|
|
63
|
+
* the band. See the module note for why this runs after the slide, not
|
|
64
|
+
* before.
|
|
65
|
+
*/
|
|
66
|
+
export declare function rewindTo(pos: number, n: number): number | null;
|
|
67
|
+
/** One arrow press, resolved into the physical positions involved. */
|
|
68
|
+
export interface RingStep {
|
|
69
|
+
/**
|
|
70
|
+
* Where the track must be placed with transitions OFF before the slide.
|
|
71
|
+
* Equal to the incoming position when no rewind is due; when it differs,
|
|
72
|
+
* the jump is invisible (both positions show the same window).
|
|
73
|
+
*/
|
|
74
|
+
readonly from: number;
|
|
75
|
+
/**
|
|
76
|
+
* Where the slide ends. May sit one past the band's end, in which case the
|
|
77
|
+
* next {@link rewindTo} brings it back.
|
|
78
|
+
*/
|
|
79
|
+
readonly to: number;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Resolve one arrow press on a ring.
|
|
83
|
+
*
|
|
84
|
+
* Any rewind still owed from the previous press is settled first, so a person
|
|
85
|
+
* clicking faster than the slide animation cannot walk the window off the
|
|
86
|
+
* rendered copies — the band always absorbs one more step.
|
|
87
|
+
*/
|
|
88
|
+
export declare function ringStep(pos: number, delta: number, n: number): RingStep;
|
|
89
|
+
/**
|
|
90
|
+
* One arrow press on a plain strip (fewer cards than fit): step by one and
|
|
91
|
+
* stay inside the scrollable range.
|
|
92
|
+
*
|
|
93
|
+
* @param maxPos - the last meaningful position, `0` when nothing scrolls.
|
|
94
|
+
*/
|
|
95
|
+
export declare function clampStep(pos: number, delta: number, maxPos: number): number;
|
|
96
|
+
//# sourceMappingURL=carousel.d.ts.map
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* @module @huaweidevtools/aishell-dsh-brand/client
|
|
9
9
|
*/
|
|
10
10
|
import type { Context as ClientContext } from '@deepseek-ai/cordis';
|
|
11
|
-
/** Required
|
|
11
|
+
/** Required services: the UI slot registry and the locale registry. */
|
|
12
12
|
export declare const inject: string[];
|
|
13
13
|
export declare function apply(ctx: ClientContext): void;
|
|
14
14
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* aishell brand locale dictionaries.
|
|
3
|
+
*
|
|
4
|
+
* The brand plugin owns its own namespace rather than reusing `aishell`
|
|
5
|
+
* (which `aishell-credentials` registers): a namespace's texts have exactly
|
|
6
|
+
* one owner, and a duplicate `(ns, locale)` registration throws.
|
|
7
|
+
*
|
|
8
|
+
* ## Why content lives in a dictionary
|
|
9
|
+
*
|
|
10
|
+
* The suggestion cards are the only strings in this plugin a person reads,
|
|
11
|
+
* and they are CONTENT rather than interface chrome — a card title, its
|
|
12
|
+
* one-line gloss, and the prompt a click inserts. They still belong here:
|
|
13
|
+
* a card that says「云资源查询」to an English reader is worse than no card,
|
|
14
|
+
* and the prompt it inserts would start an English conversation in Chinese.
|
|
15
|
+
*
|
|
16
|
+
* Chinese is the key-set source of truth; English is complete against it and
|
|
17
|
+
* is also the terminal fallback, so every locale other than `zh` reads
|
|
18
|
+
* English. That is the framework's own chain (`LOCALE_IDS = ["zh", "en"]`,
|
|
19
|
+
* with English carrying no fallback) — there is no third dictionary to write.
|
|
20
|
+
*
|
|
21
|
+
* @module @huaweidevtools/aishell-dsh-brand/client/locales
|
|
22
|
+
*/
|
|
23
|
+
/** Dictionary namespace owned by this plugin. */
|
|
24
|
+
export declare const NS: "aishell-brand";
|
|
25
|
+
/** Simplified Chinese dictionary (the key-set source of truth). */
|
|
26
|
+
export declare const zh: {
|
|
27
|
+
readonly 'suggestion.previous': "上一个示例";
|
|
28
|
+
readonly 'suggestion.next': "下一个示例";
|
|
29
|
+
readonly 'suggestion.inventory.title': "云资源查询";
|
|
30
|
+
readonly 'suggestion.inventory.gloss': "列出当前账号下的云资源";
|
|
31
|
+
readonly 'suggestion.inventory.prompt': "请列出我的华为云资源清单,按服务分类(计算、存储、网络、数据库等),标出每类资源的数量和所在区域。";
|
|
32
|
+
readonly 'suggestion.deploy.title': "部署方案推荐";
|
|
33
|
+
readonly 'suggestion.deploy.gloss': "按访问量和预算给出可落地的部署路径";
|
|
34
|
+
readonly 'suggestion.deploy.prompt': "我要部署一个轻量级 Web 应用,请对比几种可行的部署方案,说明各自的适用规模、月度成本量级和运维复杂度,并给出你的推荐及理由。";
|
|
35
|
+
readonly 'suggestion.enterprise.title': "企业上云";
|
|
36
|
+
readonly 'suggestion.enterprise.gloss': "多账号、网络分区与权限边界的整体设计";
|
|
37
|
+
readonly 'suggestion.enterprise.prompt': "请为我规划一套云上 Landing Zone 架构,覆盖账号组织结构、网络分区、权限边界与审计要求,并说明各部分的设计取舍。";
|
|
38
|
+
readonly 'suggestion.billing.title': "账单分析";
|
|
39
|
+
readonly 'suggestion.billing.gloss': "分析上个月的云资源支出";
|
|
40
|
+
readonly 'suggestion.billing.prompt': "请分析我上个月的云资源支出构成,找出占比最高的几项服务,指出其中可以优化或降配的部分,并估算调整后能节省多少。";
|
|
41
|
+
};
|
|
42
|
+
/** English dictionary. Complete against {@link zh}; also the terminal fallback. */
|
|
43
|
+
export declare const en: {
|
|
44
|
+
readonly 'suggestion.previous': "Previous example";
|
|
45
|
+
readonly 'suggestion.next': "Next example";
|
|
46
|
+
readonly 'suggestion.inventory.title': "Cloud inventory";
|
|
47
|
+
readonly 'suggestion.inventory.gloss': "List the resources in this account";
|
|
48
|
+
readonly 'suggestion.inventory.prompt': string;
|
|
49
|
+
readonly 'suggestion.deploy.title': "Deployment options";
|
|
50
|
+
readonly 'suggestion.deploy.gloss': "A workable path for your traffic and budget";
|
|
51
|
+
readonly 'suggestion.deploy.prompt': string;
|
|
52
|
+
readonly 'suggestion.enterprise.title': "Landing zone";
|
|
53
|
+
readonly 'suggestion.enterprise.gloss': "Multi-account structure, network and permission boundaries";
|
|
54
|
+
readonly 'suggestion.enterprise.prompt': string;
|
|
55
|
+
readonly 'suggestion.billing.title': "Billing analysis";
|
|
56
|
+
readonly 'suggestion.billing.gloss': "Break down last month's cloud spend";
|
|
57
|
+
readonly 'suggestion.billing.prompt': string;
|
|
58
|
+
};
|
|
59
|
+
/** Every key, derived from the zh dictionary (the source of truth). */
|
|
60
|
+
export type AishellBrandLocaleKey = keyof typeof zh;
|
|
61
|
+
declare module '@deepseek-ai/dsh-client-ui-slots' {
|
|
62
|
+
interface LocaleNamespaceMap {
|
|
63
|
+
'aishell-brand': AishellBrandLocaleKey;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=locales.d.ts.map
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Inline SVG artwork for the suggestion cards.
|
|
3
|
+
*
|
|
4
|
+
* Inline rather than an icon dependency: the strip draws four shapes, and a
|
|
5
|
+
* dependency would add a package, a version to track, and a bundle face to
|
|
6
|
+
* keep in step with the host.
|
|
7
|
+
*
|
|
8
|
+
* Every path is drawn on a 24×24 viewBox with `currentColor`, so a card
|
|
9
|
+
* decides the colour by setting `color` and nothing here hard-codes a theme
|
|
10
|
+
* value.
|
|
11
|
+
*
|
|
12
|
+
* ## Shape rules, learned by getting them wrong
|
|
13
|
+
*
|
|
14
|
+
* The first draft drew "deploy" as a box with an arrow leaving it — which
|
|
15
|
+
* reads as SHARE or export, the one meaning this card must not carry. A
|
|
16
|
+
* glyph in a row of four is read at a glance and out of context, so each one
|
|
17
|
+
* has to be recognisable on its own:
|
|
18
|
+
*
|
|
19
|
+
* - nothing may resemble the share glyph (box + outward arrow) or the
|
|
20
|
+
* external-link glyph (box + arrow through a corner);
|
|
21
|
+
* - every shape is closed and filled-ish in silhouette, because outlines
|
|
22
|
+
* at 20px in a row of four blur into each other;
|
|
23
|
+
* - no glyph carries more than three strokes, so they stay distinguishable
|
|
24
|
+
* at the size they are actually drawn.
|
|
25
|
+
*
|
|
26
|
+
* These rules are not machine-checked: rendering the glyphs needs
|
|
27
|
+
* `react-dom/server`, which this repo does not depend on, and vitest here
|
|
28
|
+
* collects only `.spec.ts` (not `.tsx`). The browser harness in
|
|
29
|
+
* `scripts/render-check/` is what actually puts them on screen.
|
|
30
|
+
*
|
|
31
|
+
* @module @huaweidevtools/aishell-dsh-brand/client/suggestion-icons
|
|
32
|
+
*/
|
|
33
|
+
import type { ReactNode } from 'react';
|
|
34
|
+
import type { SuggestionIcon } from './suggestions.ts';
|
|
35
|
+
/** Props shared by every glyph. */
|
|
36
|
+
interface IconProps {
|
|
37
|
+
/** Rendered size in px; the cards use 20. */
|
|
38
|
+
readonly size?: number;
|
|
39
|
+
}
|
|
40
|
+
/** Resolve one icon key to its glyph. */
|
|
41
|
+
export declare function SuggestionIconArt({ icon, size, }: IconProps & {
|
|
42
|
+
readonly icon: SuggestionIcon;
|
|
43
|
+
}): ReactNode;
|
|
44
|
+
export {};
|
|
45
|
+
//# sourceMappingURL=suggestion-icons.d.ts.map
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The New-Session example cards, and the shapes they need.
|
|
3
|
+
*
|
|
4
|
+
* One array drives the whole strip: add or reorder a card by editing
|
|
5
|
+
* `SUGGESTIONS` and adding its three keys to `locales.ts`, and nothing else.
|
|
6
|
+
* The row renders whatever it is given — three or fewer display side by side
|
|
7
|
+
* with no arrows, more than three become a carousel.
|
|
8
|
+
*
|
|
9
|
+
* ## This file holds no copy
|
|
10
|
+
*
|
|
11
|
+
* Every string a person reads — the card title, its one-line gloss, and the
|
|
12
|
+
* prompt a click inserts — lives in `locales.ts`, addressed by the keys here.
|
|
13
|
+
* A card whose text were inlined would be readable in exactly one language,
|
|
14
|
+
* and the prompt it inserted would start a conversation in that language no
|
|
15
|
+
* matter what the reader's locale was.
|
|
16
|
+
*
|
|
17
|
+
* The three keys per card are separate rather than one blob because the
|
|
18
|
+
* surfaces differ: the card shows `title` and `gloss` (both clamped — one
|
|
19
|
+
* line and two lines — so a long string ellipsizes instead of breaking the
|
|
20
|
+
* row), while `prompt` goes to the composer and is never displayed on the
|
|
21
|
+
* card. A prompt that only restates its title makes the click pointless;
|
|
22
|
+
* written as a pair, the prompt carries the context and the expected output
|
|
23
|
+
* that make the first message worth sending without editing.
|
|
24
|
+
*
|
|
25
|
+
* ## Sizing, when editing copy
|
|
26
|
+
*
|
|
27
|
+
* Three cards share one row, which at the default column leaves roughly 150px
|
|
28
|
+
* per title — about seven CJK glyphs, or noticeably more Latin ones. Measured
|
|
29
|
+
* against the shipped set: every title fits at 560px and above, and all four
|
|
30
|
+
* clip below ~460px. Keep them within a couple of characters of each other —
|
|
31
|
+
* the longest one is otherwise the only card that ever shows an ellipsis,
|
|
32
|
+
* which reads as a bug rather than as a long name.
|
|
33
|
+
*
|
|
34
|
+
* @module @huaweidevtools/aishell-dsh-brand/client/suggestions
|
|
35
|
+
*/
|
|
36
|
+
import type { AishellBrandLocaleKey } from './locales.ts';
|
|
37
|
+
/** One example card: what it looks like, and what a click inserts. */
|
|
38
|
+
export interface Suggestion {
|
|
39
|
+
/**
|
|
40
|
+
* Stable identity for React keys and for the carousel's position maths.
|
|
41
|
+
* Not shown to anyone — it names the dictionary key prefix, so renaming it
|
|
42
|
+
* means renaming three keys in `locales.ts`.
|
|
43
|
+
*/
|
|
44
|
+
readonly id: string;
|
|
45
|
+
/** Icon key resolved by {@link SuggestionIconArt}. */
|
|
46
|
+
readonly icon: SuggestionIcon;
|
|
47
|
+
/** Dictionary key for the card's one-line title. */
|
|
48
|
+
readonly titleKey: AishellBrandLocaleKey;
|
|
49
|
+
/** Dictionary key for the line under the title. */
|
|
50
|
+
readonly glossKey: AishellBrandLocaleKey;
|
|
51
|
+
/** Dictionary key for the text inserted into the composer. */
|
|
52
|
+
readonly promptKey: AishellBrandLocaleKey;
|
|
53
|
+
}
|
|
54
|
+
/** The icon set this strip can draw. Keys are local to this plugin. */
|
|
55
|
+
export type SuggestionIcon = 'cloud' | 'deploy' | 'architecture' | 'cost';
|
|
56
|
+
/**
|
|
57
|
+
* The cards, in display order.
|
|
58
|
+
*
|
|
59
|
+
* Order matters only for the ring's starting window: the strip opens on the
|
|
60
|
+
* first {@link VISIBLE} cards, so the first entries are the ones a person
|
|
61
|
+
* sees without pressing an arrow.
|
|
62
|
+
*/
|
|
63
|
+
export declare const SUGGESTIONS: readonly Suggestion[];
|
|
64
|
+
//# sourceMappingURL=suggestions.d.ts.map
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@huaweidevtools/aishell-dsh-brand",
|
|
3
3
|
"description": "AI Shell brand reskin for DSH web — replaces sidebar and hero brand marks with AI Shell SVG",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.5",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -30,7 +30,8 @@
|
|
|
30
30
|
"inject": [
|
|
31
31
|
"@deepseek-ai/dsh-client-ui-renderer",
|
|
32
32
|
"@deepseek-ai/dsh-client-ui-sidebar",
|
|
33
|
-
"@deepseek-ai/dsh-client-ui-conversation"
|
|
33
|
+
"@deepseek-ai/dsh-client-ui-conversation",
|
|
34
|
+
"@deepseek-ai/dsh-client-locale"
|
|
34
35
|
],
|
|
35
36
|
"platform": "web"
|
|
36
37
|
},
|
|
@@ -44,10 +45,11 @@
|
|
|
44
45
|
},
|
|
45
46
|
"devDependencies": {
|
|
46
47
|
"@deepseek-ai/cordis": "^4.0.4",
|
|
47
|
-
"@deepseek-ai/dsh-client-
|
|
48
|
-
"@deepseek-ai/dsh-client-ui-
|
|
49
|
-
"@deepseek-ai/dsh-client-ui-
|
|
50
|
-
"@deepseek-ai/dsh-client-ui-
|
|
48
|
+
"@deepseek-ai/dsh-client-locale": "0.2.0-rc.1 || 0.2.1-rc.1 || 0.2.1-rc.2 || 0.2.1",
|
|
49
|
+
"@deepseek-ai/dsh-client-ui-conversation": "0.2.0-rc.1 || 0.2.1-rc.1 || 0.2.1-rc.2 || 0.2.1",
|
|
50
|
+
"@deepseek-ai/dsh-client-ui-renderer": "0.2.0-rc.1 || 0.2.1-rc.1 || 0.2.1-rc.2 || 0.2.1",
|
|
51
|
+
"@deepseek-ai/dsh-client-ui-sidebar": "0.2.0-rc.1 || 0.2.1-rc.1 || 0.2.1-rc.2 || 0.2.1",
|
|
52
|
+
"@deepseek-ai/dsh-client-ui-slots": "0.2.0-rc.1 || 0.2.1-rc.1 || 0.2.1-rc.2 || 0.2.1",
|
|
51
53
|
"@types/react": "~18.3.1",
|
|
52
54
|
"react": "^18.2.0",
|
|
53
55
|
"tsdown": "^0.10.0",
|