dsh-gpt-image-playground 0.2.7 → 0.2.8

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/README.md CHANGED
@@ -4,9 +4,11 @@
4
4
  [![license](https://img.shields.io/npm/l/dsh-gpt-image-playground)](LICENSE)
5
5
  [![node](https://img.shields.io/node/v/dsh-gpt-image-playground)](package.json)
6
6
 
7
- 把 [CookSleep/gpt_image_playground](https://github.com/CookSleep/gpt_image_playground) 的**原版工作台**装进 [DeepSeek Harness](https://github.com/deepseek-ai)(DSH):左栏多一个「生图工作台」,点开就是完整的画廊 / Agent 双模式、参考图与遮罩编辑、多供应商、收藏夹、历史管理。
7
+ 支持 **GPT Image**、**Gemini(Nano Banana)** 和 **Grok** 的图片生成与编辑工具,支持官方接口、OpenAI 兼容接口、api.toolify-ai.com 与自定义 HTTP 供应商。支持文本生图、参考图编辑、画板标注、遮罩编辑与 Agent 多轮对话,图片和历史记录保存在本地。
8
8
 
9
- 界面与功能来自上游官方构建(v0.8.9,原样 vendor),插件自己只负责**同源托管**和**可选的 API 代理**。
9
+ 装进 [DeepSeek Harness](https://github.com/deepseek-ai)(DSH)后,左栏多一个「生图工作台」,点开就是完整界面。
10
+
11
+ 界面与功能来自上游官方构建(v0.9.0,原样 vendor),插件自己只负责**同源托管**和**可选的 API 代理**。
10
12
 
11
13
  ![工作台](docs/screenshot-gallery.png)
12
14
 
@@ -10,7 +10,7 @@ publishing or shipping it.
10
10
  - Source: https://github.com/CookSleep/gpt_image_playground
11
11
  - Build redistributed: `vendor-app/` — the official production build published
12
12
  at https://cooksleep.github.io/gpt_image_playground/ (application version
13
- **v0.8.9**, per the build's own service-worker cache tag)
13
+ **v0.9.0**, per the build's own service-worker cache tag)
14
14
  - License: MIT
15
15
 
16
16
  Changes made to the redistributed build:
@@ -29,10 +29,12 @@ Changes made to the redistributed build:
29
29
  anchor loses `href`/`target`/`rel`)
30
30
  - the settings "关于" tab
31
31
  - the settings header's upstream version, replaced with this plugin's version
32
+ - 设置 → 习惯配置 → the whole "更新" group (automatic update check), which only
33
+ feeds the hidden NEW badge
32
34
  4. One element is **added** rather than removed: a red hint next to
33
- 设置 → API 配置 → 当前配置 ("建议使用 ToolifyAi API 高效稳定") that links to
34
- https://api.toolify-ai.com. It is injected by `lib/client.js` and is not part
35
- of the upstream build.
35
+ 设置 → API 配置 → 当前配置 ("建议使用 ToolifyAi API 高效稳定,注册享优惠") with the
36
+ ToolifyAi logo, linking to https://api.toolify-ai.com. It is injected by
37
+ `lib/client.js` and is not part of the upstream build.
36
38
 
37
39
  No other files of the build were edited.
38
40
 
package/lib/client.js CHANGED
@@ -49,15 +49,20 @@ window.__ModuleLoader__.load({
49
49
  'button[data-dsh-gipg-about="1"]',
50
50
  'header button[title^="新版本"]',
51
51
  'header h1 > button[class*="bg-red-500"]',
52
+ // 设置 → 习惯配置 → 「更新」分组(自动检查更新),只服务于被隐藏的 NEW 角标。
53
+ 'section[data-dsh-gipg-update-section="1"]',
52
54
  ]
53
55
  const TRIM_STYLE_ID = 'dsh-gipg-trim'
54
56
  const ABOUT_LABEL = '关于'
57
+ const UPDATE_SECTION_LABEL = '更新'
58
+ const UPDATE_SECTION_ATTR = 'data-dsh-gipg-update-section'
55
59
 
56
60
  /** Provider hint appended to the "当前配置" row of 设置 → API 配置. */
57
61
  const CURRENT_PROFILE_LABEL = '当前配置'
58
62
  const TIP_ATTR = 'data-dsh-gipg-tip'
59
- const TIP_TEXT = '建议使用 ToolifyAi API 高效稳定'
63
+ const TIP_TEXT = '建议使用 ToolifyAi API 高效稳定,注册享优惠'
60
64
  const TIP_URL = 'https://api.toolify-ai.com'
65
+ const TIP_LOGO = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyBpZD0iX+WbvuWxgl8xIiBkYXRhLW5hbWU9IuWbvuWxgiAxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2ZXJzaW9uPSIxLjEiIHZpZXdCb3g9IjAgMCAyODQgNzMiPgogIDxkZWZzPgogICAgPHN0eWxlPgogICAgICAuY2xzLTEgewogICAgICAgIGNsaXAtcGF0aDogdXJsKCNjbGlwcGF0aCk7CiAgICAgIH0KCiAgICAgIC5jbHMtMiB7CiAgICAgICAgZmlsbDogIzE1MTUxNTsKICAgICAgICBmb250LWZhbWlseTogU291cmNlSGFuU2Fuc0NOLUhlYXZ5LUdCcGMtRVVDLUgsICdTb3VyY2UgSGFuIFNhbnMgQ04nOwogICAgICAgIGZvbnQtd2VpZ2h0OiA4MDA7CiAgICAgIH0KCiAgICAgIC5jbHMtMiwgLmNscy0zIHsKICAgICAgICBpc29sYXRpb246IGlzb2xhdGU7CiAgICAgIH0KCiAgICAgIC5jbHMtNCB7CiAgICAgICAgZmlsbDogbm9uZTsKICAgICAgfQoKICAgICAgLmNscy00LCAuY2xzLTUsIC5jbHMtNiwgLmNscy03IHsKICAgICAgICBzdHJva2Utd2lkdGg6IDBweDsKICAgICAgfQoKICAgICAgLmNscy01IHsKICAgICAgICBmaWxsOiAjMDAwOwogICAgICB9CgogICAgICAuY2xzLTYgewogICAgICAgIGZpbGw6ICMyZTc0ZmY7CiAgICAgICAgZmlsbC1ydWxlOiBldmVub2RkOwogICAgICB9CgogICAgICAuY2xzLTggewogICAgICAgIGZvbnQtc2l6ZTogNDhweDsKICAgICAgfQoKICAgICAgLmNscy05IHsKICAgICAgICBmb250LXNpemU6IDQ0LjhweDsKICAgICAgfQoKICAgICAgLmNscy0xMCB7CiAgICAgICAgZGlzcGxheTogbm9uZTsKICAgICAgfQoKICAgICAgLmNscy03IHsKICAgICAgICBmaWxsOiAjNzE1MGU2OwogICAgICB9CiAgICA8L3N0eWxlPgogICAgPGNsaXBQYXRoIGlkPSJjbGlwcGF0aCI+CiAgICAgIDxjaXJjbGUgY2xhc3M9ImNscy00IiBjeD0iNDMiIGN5PSIzNyIgcj0iMzQuOSIvPgogICAgPC9jbGlwUGF0aD4KICA8L2RlZnM+CiAgPGcgY2xhc3M9ImNscy0xMCI+CiAgICA8cGF0aCBpZD0iX+W5tumbhiIgZGF0YS1uYW1lPSLlubbpm4YiIGNsYXNzPSJjbHMtNiIgZD0iTTY4LDguNWMwLTQuNywzLjgtOC41LDguNS04LjVzOC41LDMuOCw4LjUsOC41LTMuOCw4LjUtOC41LDguNS0yLjItLjItMy4zLS42bC0xNS4xLDEyLjZjMS44LDIuNywyLjgsNiwyLjgsOS42cy0xLjUsOC0zLjksMTFsNS4xLDUuNGMxLjUtMS4yLDMuMy0xLjksNS4zLTEuOSw0LjcsMCw4LjUsMy44LDguNSw4LjVzLTMuOCw4LjUtOC41LDguNS04LjUtMy44LTguNS04LjUuMy0yLjQuNy0zLjRsLTUuNS01LjhjLTMsMi4zLTYuNywzLjctMTAuNywzLjdzLTkuNy0yLjItMTIuOS01LjZsLTguNiw2LjZjLjYsMS40LjksMi45LjksNC41LDAsNi4zLTUuMSwxMS41LTExLjUsMTEuNVMwLDY3LjgsMCw2MS41czUuMi0xMS41LDExLjUtMTEuNSw2LjMsMS40LDguNCwzLjZsOC40LTYuNWMtMS41LTIuNi0yLjMtNS41LTIuMy04LjYsMC05LjcsNy44LTE3LjUsMTcuNS0xNy41czksMS45LDEyLjEsNC45bDE0LjMtMTJjLTEuMi0xLjUtMS45LTMuNC0xLjktNS40Wk0xMCwxNC41YzAtNS4yLDQuMi05LjUsOS41LTkuNXM5LjUsNC4yLDkuNSw5LjUtNC4yLDkuNS05LjUsOS41LTkuNS00LjItOS41LTkuNVoiLz4KICAgIDxhIHhsaW5rOmhyZWY9Imh0dHBzOi8vIj4KICAgICAgPGcgY2xhc3M9ImNscy0zIj4KICAgICAgICA8dGV4dCBjbGFzcz0iY2xzLTIiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDEwNSA1Mi4zKSI+PHRzcGFuIGNsYXNzPSJjbHMtOCIgeD0iMCIgeT0iMCI+57KSPC90c3Bhbj48dHNwYW4gY2xhc3M9ImNscy05IiB4PSI0OCIgeT0iMCI+5a2Q5a+86IiqPC90c3Bhbj48L3RleHQ+CiAgICAgIDwvZz4KICAgIDwvYT4KICA8L2c+CiAgPHBhdGggY2xhc3M9ImNscy03IiBkPSJNNDMuMSw1OC4yYy0xMS43LDAtMjEuMy05LjYtMjEuMy0yMS4zczkuNi0yMS4zLDIxLjMtMjEuMywyMS4zLDkuNiwyMS4zLDIxLjMtOS42LDIxLjMtMjEuMywyMS4zWk00My4xLDI1LjJjLTYuNSwwLTExLjcsNS4zLTExLjcsMTEuN3M1LjMsMTEuNywxMS43LDExLjcsMTEuNy01LjMsMTEuNy0xMS43LTUuMy0xMS43LTExLjctMTEuN1oiLz4KICA8ZyBjbGFzcz0iY2xzLTEiPgogICAgPGc+CiAgICAgIDxjaXJjbGUgY2xhc3M9ImNscy03IiBjeD0iMTEiIGN5PSIyMy42IiByPSI5LjQiLz4KICAgICAgPGNpcmNsZSBjbGFzcz0iY2xzLTciIGN4PSIxMC44IiBjeT0iNTAuNSIgcj0iOS40Ii8+CiAgICAgIDxjaXJjbGUgY2xhc3M9ImNscy03IiBjeD0iMjkuNiIgY3k9IjY5LjEiIHI9IjkuNCIvPgogICAgICA8Y2lyY2xlIGNsYXNzPSJjbHMtNyIgY3g9IjU2LjMiIGN5PSI2OS4xIiByPSI5LjQiLz4KICAgICAgPGNpcmNsZSBjbGFzcz0iY2xzLTciIGN4PSI3NS40IiBjeT0iNTAuNSIgcj0iOS40Ii8+CiAgICAgIDxjaXJjbGUgY2xhc3M9ImNscy03IiBjeD0iNzUuNCIgY3k9IjIzLjgiIHI9IjkuNCIvPgogICAgICA8Y2lyY2xlIGNsYXNzPSJjbHMtNyIgY3g9IjU2LjYiIGN5PSI1IiByPSI5LjQiLz4KICAgICAgPGNpcmNsZSBjbGFzcz0iY2xzLTciIGN4PSIzMC42IiBjeT0iNC45IiByPSI5LjQiLz4KICAgIDwvZz4KICA8L2c+CiAgPGc+CiAgICA8cGF0aCBjbGFzcz0iY2xzLTUiIGQ9Ik0xMTAuNywyMi40bC0uNCwyLjFjLS4xLjYtLjcsMS4xLTEuMywxLjFoLTUuNWMtLjYsMC0xLjIuNS0xLjMsMS4xbC00LjQsMjQuOWMtLjEuNi0uNywxLjEtMS4zLDEuMWgtM2MtLjgsMC0xLjQtLjctMS4zLTEuNmw0LjQtMjRjLjEtLjgtLjUtMS42LTEuMy0xLjZoLTQuN2MtLjgsMC0xLjQtLjctMS4zLTEuNWwuNC0yLjFjLjEtLjYuNy0xLjEsMS4zLTEuMWgxOC41Yy44LDAsMS40LjcsMS4zLDEuNVoiLz4KICAgIDxwYXRoIGNsYXNzPSJjbHMtNSIgZD0iTTExOS4zLDUzYy0yLjcsMC00LjctLjQtNS43LTEuMy0xLjItLjgtMS44LTIuMi0xLjgtNC4zcy4yLTIuNC41LTQuNGwxLjEtNi4yYy4yLTEuNy41LTMuMSwxLTQuMS4zLTEsLjktMS44LDEuNi0yLjUuNi0uNSwxLjQtLjksMi41LTEuMnMuNCwwLC41LS4xYzEuMS0uMiwyLjUtLjMsNC4yLS4zaDIuOGMyLjcsMCw0LjcuNCw1LjksMS4zLDEuMS45LDEuNiwyLjMsMS42LDQuM3MtLjIsMi42LS41LDQuNGwtMS4xLDYuMmMtLjMsMi4xLS43LDMuNi0xLjEsNC40LS40LjktLjksMS42LTEuNSwyLjEtLjcuNS0xLjUuOS0yLjYsMS4xLTEuMi4zLTIuNy41LTQuNi41aC0yLjhaTTEyMC42LDQ4LjhoMmMuOCwwLDEuNCwwLDItLjIuNC0uMS44LS4zLDEtLjcuNS0uNSwxLTEuNiwxLjMtMy4xbDEtNi4yYy4zLTEuNi41LTIuOS41LTMuOHMtLjMtMS4zLS44LTEuNmMtLjUtLjItMS41LS4zLTIuOC0uM2gtMS44czAsMCwwLDBjLTIuMSwwLTMuOCwxLjUtNC4zLDMuNXMwLC4zLDAsLjRsLTEsNi4yYy0uMywxLjgtLjUsMy0uNSwzLjZzLjMsMS40LjgsMS42Yy40LjMsMS40LjUsMi44LjVaIi8+CiAgICA8cGF0aCBjbGFzcz0iY2xzLTUiIGQ9Ik0xNDMuNCw1M2MtMi43LDAtNC42LS40LTUuNy0xLjMtMS4yLS44LTEuOC0yLjItMS44LTQuM3MuMi0yLjQuNS00LjRsMS4xLTYuMmMuMi0xLjcuNS0zLjEsMS00LjEuMy0xLC45LTEuOCwxLjYtMi41LjYtLjUsMS40LS45LDIuNS0xLjJzLjQsMCwuNS0uMWMxLjEtLjIsMi40LS4zLDQuMi0uM2gyLjhjMi43LDAsNC43LjQsNS45LDEuMywxLjEuOSwxLjYsMi4zLDEuNiw0LjNzLS4yLDIuNi0uNSw0LjRsLTEuMSw2LjJjLS4zLDIuMS0uNywzLjYtMS4xLDQuNC0uNC45LS45LDEuNi0xLjUsMi4xLS43LjUtMS41LjktMi42LDEuMS0xLjIuMy0yLjcuNS00LjYuNWgtMi44Wk0xNDQuNyw0OC44aDJjLjgsMCwxLjQsMCwyLS4yLjQtLjEuOC0uMywxLS43LjUtLjUsMS0xLjYsMS4zLTMuMWwxLTYuMmMuMy0xLjYuNS0yLjkuNS0zLjhzLS4zLTEuMy0uOC0xLjZjLS41LS4yLTEuNS0uMy0yLjgtLjNoLTEuOHMwLDAsMCwwYy0yLjEsMC0zLjgsMS41LTQuMywzLjVzMCwuMywwLC40bC0xLDYuMmMtLjMsMS44LS41LDMtLjUsMy42cy4zLDEuNC44LDEuNmMuNC4zLDEuNC41LDIuOC41WiIvPgogICAgPHBhdGggY2xhc3M9ImNscy01IiBkPSJNMTY2LjksNTIuN2MtMi40LDAtNC4xLS4zLTUuMS0xLTEuMS0uNy0xLjYtMS45LTEuNi0zLjZzLjItMi44LjctNS40bDQuMS0yMi40Yy4xLS42LjctMS4xLDEuMy0xLjFoMi40Yy44LDAsMS40LjcsMS4zLDEuNWwtMy44LDIxLjljLS40LDIuMS0uNywzLjQtLjcsNC4xcy4xLjguMywxYy4yLjMuNi41LDEuMS41LjQuMSwxLjMuMiwyLjUuMmguM2MuOSwwLDEuNiwxLDEuMiwxLjhsLS43LDEuNmMtLjIuNS0uNy44LTEuMi44aC0yLjFaIi8+CiAgICA8cGF0aCBjbGFzcz0iY2xzLTUiIGQ9Ik0xNzMuNyw1MS4ybDMuOC0yMS4xYy4xLS42LjctMS4xLDEuMy0xLjFoMi40Yy44LDAsMS40LjcsMS4zLDEuNWwtMy42LDIxLjFjLS4xLjYtLjcsMS4xLTEuMywxLjFoLTIuNmMtLjgsMC0xLjQtLjctMS4zLTEuNlpNMTc4LjUsMjMuNGwuNS0yLjhjLjEtLjYuNy0xLjEsMS4zLTEuMWgyLjdjLjgsMCwxLjQuNywxLjMsMS42bC0uNSwyLjhjLS4xLjYtLjcsMS4xLTEuMywxLjFoLTIuN2MtLjgsMC0xLjQtLjctMS4zLTEuNloiLz4KICAgIDxwYXRoIGNsYXNzPSJjbHMtNSIgZD0iTTE5Ny4xLDI0LjJjLS40LjQtLjgsMS41LTEuMSwzLjNsLS4zLDEuNWg0LjZjLjgsMCwxLjUuOCwxLjMsMS42bC0uMywxLjZjLS4xLjYtLjcsMS4xLTEuMywxLjFoLTMuOWMtLjYsMC0xLjIuNS0xLjMsMS4xbC0zLjEsMTcuM2MtLjEuNi0uNywxLjEtMS4zLDEuMWgtMi42Yy0uOCwwLTEuNC0uNy0xLjMtMS42bDIuOS0xNi40Yy4xLS44LS41LTEuNi0xLjMtMS42aDBjLS44LDAtMS40LS43LTEuMy0xLjVsLjItMS42YzAtLjYuNy0xLjEsMS4zLTEuMWguOWMuNiwwLDEuMi0uNCwxLjMtMXYtLjRjLjUtMi4yLDEtMy43LDEuNC00LjYuMy0uOS44LTEuNiwxLjMtMi4xczEtLjgsMS45LTEuMS4xLDAsLjIsMGMuOC0uMiwyLS4zLDMuNy0uM2gzLjRjLjgsMCwxLjQuNywxLjMsMS41bC0uMiwxLjZjMCwuNi0uNywxLjEtMS4zLDEuMWgtNGMtLjUuMS0uOS4zLTEuMS43WiIvPgogICAgPHBhdGggY2xhc3M9ImNscy01IiBkPSJNMjI0LjQsMjguOWgyLjZjLjgsMCwxLjQuNywxLjMsMS41bC00LDIyLjlzMCwwLDAsMGMtLjMsMS40LS43LDIuNi0xLjEsMy42LS41LDEtMS4zLDEuNy0yLjMsMi4zLTEsLjctMi42LDEtNC45LDFoLTcuOWMtLjcsMC0xLjItLjUtMS4zLTEuMWwtLjItMS42Yy0uMS0uOC41LTEuNSwxLjMtMS41aDdjMS4zLDAsMi4yLS4xLDIuOC0uMy40LS4yLjgtLjYsMS0xLjEuMi0uNC40LTEuMy43LTIuNWgwYy4yLS45LS41LTEuNi0xLjMtMS42aC00LjNjLTIuNywwLTQuNy0uNC01LjctMS4zLTEuMi0uOS0xLjgtMi4zLTEuOC00LjNzLjItMi40LjUtNC40bDEuOC0xMC40Yy4xLS42LjctMS4xLDEuMy0xLjFoMi42Yy44LDAsMS40LjcsMS4zLDEuNWwtMS43LDkuOWMtLjMsMS42LS41LDIuOC0uNSwzLjZzLjMsMS40LjgsMS42Yy40LjMsMS40LjUsMi44LjVoNC4zYy42LDAsMS4yLS41LDEuMy0xLjFsMi42LTE1Yy4xLS42LjctMS4xLDEuMy0xLjFaIi8+CiAgICA8cGF0aCBjbGFzcz0iY2xzLTciIGQ9Ik0yNDguMywyMC43YzMuNCwwLDUuOC41LDcuMiwxLjUsMS4zLDEsMiwyLjcsMiw1LjFzLS4yLDMuMy0uNyw1LjZsLTMuMiwxOC43Yy0uMS43LS43LDEuMi0xLjQsMS4yaC0yLjljLS45LDAtMS41LS44LTEuNC0xLjZsMS41LTcuN2MuMy0xLjUtLjgtMi44LTIuMy0yLjhoLTcuNWMtLjcsMC0xLjMuNS0xLjQsMS4ybC0xLjcsOS44Yy0uMS43LS43LDEuMi0xLjQsMS4yaC0yLjdjLS45LDAtMS41LS44LTEuNC0xLjZsMy44LTIxYy41LTMuMSwxLjItNS4xLDItNi4yLjctMSwxLjUtMS43LDIuNS0yLjEsMS40LS43LDQtMSw3LjctMWgxLjNaTTI0Mi4yLDM2LjFoNy4yYy43LDAsMS4yLS41LDEuNC0xLjFsLjQtMi4yYy40LTIuMi43LTMuOC43LTQuOXMwLDAsMCwwYzAtMS4zLTEtMi4zLTIuMy0yLjVzLTEuMy0uMS0yLjItLjFoLTEuMWMtMi4yLDAtMy43LjMtNC40LDEtLjMuMi0uNi42LS44LDEuMS0uMy43LS43LDEuOS0xLDMuNmwtLjMsMi4xYy0uMywxLjYsMSwzLDIuNSwzWiIvPgogICAgPHBhdGggY2xhc3M9ImNscy03IiBkPSJNMjU5LjQsNTEuMmwzLjctMjAuN2MuMi0uOS45LTEuNSwxLjgtMS41aDEuNWMxLjEsMCwxLjksMSwxLjcsMmwtMy42LDIwLjdjLS4xLjYtLjYsMS4xLTEuMywxLjFoLTIuN2MtLjgsMC0xLjQtLjctMS4zLTEuNVpNMjY0LjEsMjMuNWwuNS0yLjljLjEtLjYuNi0xLDEuMy0xaDIuOGMuOCwwLDEuNC43LDEuMywxLjVsLS41LDIuOWMtLjEuNi0uNiwxLTEuMywxaC0yLjhjLS44LDAtMS40LS43LTEuMy0xLjVaIi8+CiAgPC9nPgo8L3N2Zz4='
61
66
 
62
67
  /** What the settings header shows: the plugin's own version, nothing else. */
63
68
  function versionLabel(pluginVersion) {
@@ -89,6 +94,13 @@ window.__ModuleLoader__.load({
89
94
  for (const button of doc.querySelectorAll('button')) {
90
95
  if ((button.textContent || '').trim() === ABOUT_LABEL) button.setAttribute('data-dsh-gipg-about', '1')
91
96
  }
97
+ // 设置 → 习惯配置 → 「更新」分组的标题是文本,CSS 选不到,
98
+ // 所以先给整个 section 打标记,再由样式表整段隐藏。
99
+ for (const heading of doc.querySelectorAll('h4')) {
100
+ if ((heading.textContent || '').trim() !== UPDATE_SECTION_LABEL) continue
101
+ const section = heading.closest('section')
102
+ if (section && !section.hasAttribute(UPDATE_SECTION_ATTR)) section.setAttribute(UPDATE_SECTION_ATTR, '1')
103
+ }
92
104
  // The product title is a link to the upstream repository on the
93
105
  // standalone site. Inside DSH it should read as a plain label, so the
94
106
  // anchor keeps its text and styling but loses every navigational bit.
@@ -111,22 +123,37 @@ window.__ModuleLoader__.load({
111
123
  tip.href = TIP_URL
112
124
  tip.target = '_blank'
113
125
  tip.rel = 'noopener noreferrer'
114
- tip.textContent = TIP_TEXT
115
126
  tip.title = TIP_URL
116
127
  tip.style.cssText = [
117
128
  'margin-left:4px',
118
- 'font-size:11px',
119
- 'line-height:1.35',
129
+ 'display:inline-flex',
130
+ 'align-items:center',
131
+ 'gap:5px',
132
+ 'font-size:13px',
133
+ 'line-height:1.4',
120
134
  'color:#ef4444',
121
135
  'text-decoration:none',
122
136
  'cursor:pointer',
123
137
  'flex:none',
124
138
  ].join(';')
139
+
140
+ const logo = doc.createElement('img')
141
+ logo.src = TIP_LOGO
142
+ logo.alt = ''
143
+ logo.setAttribute('aria-hidden', 'true')
144
+ logo.style.cssText = 'height:18px;width:auto;display:block;flex:none'
145
+ // A blocked CDN must not leave a broken-image icon or shift the row.
146
+ logo.addEventListener('error', () => logo.remove())
147
+
148
+ const label = doc.createElement('span')
149
+ label.textContent = TIP_TEXT
150
+
151
+ tip.append(logo, label)
125
152
  tip.addEventListener('mouseenter', () => {
126
- tip.style.textDecoration = 'underline'
153
+ label.style.textDecoration = 'underline'
127
154
  })
128
155
  tip.addEventListener('mouseleave', () => {
129
- tip.style.textDecoration = 'none'
156
+ label.style.textDecoration = 'none'
130
157
  })
131
158
  row.appendChild(tip)
132
159
  break
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "dsh-gpt-image-playground",
3
- "version": "0.2.7",
4
- "description": "GPT Image Playground as a DeepSeek Harness plugin: the upstream image generation and editing workbench, vendored, served same-origin, with an optional API proxy.",
3
+ "version": "0.2.8",
4
+ "description": "Image generation and editing for GPT Image, Gemini (Nano Banana) and Grok, with official, OpenAI-compatible, api.toolify-ai.com and custom HTTP providers. Text-to-image, reference-image editing, canvas annotation, mask editing and Agent multi-turn chat, with images and history kept on your machine.",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
7
7
  "exports": {
@@ -31,7 +31,7 @@
31
31
  },
32
32
  "upstream": {
33
33
  "name": "gpt-image-playground",
34
- "version": "0.8.9",
34
+ "version": "0.9.0",
35
35
  "repository": "https://github.com/CookSleep/gpt_image_playground",
36
36
  "build": "vendor-app"
37
37
  }