@ddrinnova/agentsgt-widget 0.1.7 → 0.1.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 +154 -105
- package/dist/widget.css +1 -0
- package/dist/widget.es.js +20774 -63721
- package/dist/widget.umd.js +133 -498
- package/package.json +14 -6
- package/dist/agentsgt-widget.css +0 -1
package/README.md
CHANGED
|
@@ -1,148 +1,197 @@
|
|
|
1
|
-
|
|
1
|
+
<div align="center">
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
# @ddrinnova/agentsgt-widget
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
**Drop-in chat widget for [AgentsGT](https://agentsgt.com) AI agents.**
|
|
6
|
+
|
|
7
|
+
Embed a fully-featured AI assistant on any website with a single script tag.
|
|
8
|
+
|
|
9
|
+
[](https://www.npmjs.com/package/@ddrinnova/agentsgt-widget)
|
|
10
|
+
[](https://bundlephobia.com/package/@ddrinnova/agentsgt-widget)
|
|
11
|
+
[](https://github.com/ddrinnova/agentsgt-widget/blob/main/LICENSE)
|
|
12
|
+
|
|
13
|
+
</div>
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Features
|
|
18
|
+
|
|
19
|
+
- **3 display modes** — Popup bubble, sidebar panel, or inline chat
|
|
20
|
+
- **Streaming responses** — Real-time AI output via Vercel AI SDK
|
|
21
|
+
- **Markdown rendering** — Rich text, code blocks, tables, and lists
|
|
22
|
+
- **Tool display** — Web search results, image generation, document lookup
|
|
23
|
+
- **Multi-language** — Auto-detects agent language (EN, ES, FR, DE, PT, IT)
|
|
24
|
+
- **Session persistence** — Conversations survive page refreshes
|
|
25
|
+
- **Theming** — Customize colors to match your brand
|
|
26
|
+
- **Lightweight** — ~150 KB gzipped, zero external CSS conflicts
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## Quick Start
|
|
31
|
+
|
|
32
|
+
### Script Tag
|
|
33
|
+
|
|
34
|
+
The fastest way to add an agent to any site:
|
|
35
|
+
|
|
36
|
+
```html
|
|
37
|
+
<div id="agent-chat"></div>
|
|
38
|
+
|
|
39
|
+
<script src="https://unpkg.com/@ddrinnova/agentsgt-widget/dist/widget.umd.js"></script>
|
|
40
|
+
<link rel="stylesheet" href="https://unpkg.com/@ddrinnova/agentsgt-widget/dist/widget.css" />
|
|
41
|
+
|
|
42
|
+
<script>
|
|
43
|
+
AgentSGTWidget.mountApp(document.getElementById('agent-chat'), {
|
|
44
|
+
runtimeUrl: 'https://agentsgt.com/api/v1/agents/chat/YOUR_AGENT_ID',
|
|
45
|
+
apiKey: 'pk_xxx:sk_xxx',
|
|
46
|
+
});
|
|
47
|
+
</script>
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### npm Install
|
|
6
51
|
|
|
7
52
|
```bash
|
|
8
|
-
npm install @agentsgt
|
|
53
|
+
npm install @ddrinnova/agentsgt-widget
|
|
9
54
|
```
|
|
10
55
|
|
|
11
|
-
|
|
56
|
+
```tsx
|
|
57
|
+
import { mountApp } from '@ddrinnova/agentsgt-widget';
|
|
58
|
+
import '@ddrinnova/agentsgt-widget/dist/widget.css';
|
|
59
|
+
|
|
60
|
+
const unmount = mountApp(document.getElementById('agent-chat')!, {
|
|
61
|
+
runtimeUrl: 'https://agentsgt.com/api/v1/agents/chat/YOUR_AGENT_ID',
|
|
62
|
+
apiKey: 'pk_xxx:sk_xxx',
|
|
63
|
+
uiMode: 'popup',
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
// Call unmount() to remove the widget later
|
|
67
|
+
```
|
|
12
68
|
|
|
13
|
-
###
|
|
69
|
+
### React Component
|
|
14
70
|
|
|
15
|
-
```
|
|
16
|
-
import
|
|
17
|
-
import
|
|
71
|
+
```tsx
|
|
72
|
+
import App from '@ddrinnova/agentsgt-widget';
|
|
73
|
+
import '@ddrinnova/agentsgt-widget/dist/widget.css';
|
|
18
74
|
|
|
19
|
-
function
|
|
75
|
+
function MyPage() {
|
|
20
76
|
return (
|
|
21
|
-
<
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
77
|
+
<App
|
|
78
|
+
runtimeUrl="https://agentsgt.com/api/v1/agents/chat/YOUR_AGENT_ID"
|
|
79
|
+
apiKey="pk_xxx:sk_xxx"
|
|
80
|
+
uiMode="popup"
|
|
81
|
+
title="Support"
|
|
82
|
+
initialMessage="Hi! How can I help you today?"
|
|
83
|
+
theme={{ primaryColor: '#7C3AED' }}
|
|
84
|
+
/>
|
|
29
85
|
);
|
|
30
86
|
}
|
|
31
87
|
```
|
|
32
88
|
|
|
33
|
-
###
|
|
34
|
-
|
|
35
|
-
Add a container to your HTML:
|
|
89
|
+
### Loader (dynamically load widget assets)
|
|
36
90
|
|
|
37
91
|
```html
|
|
38
|
-
<div id="agent-widget
|
|
92
|
+
<div id="agent-widget"></div>
|
|
39
93
|
|
|
40
94
|
<script>
|
|
41
95
|
window.onload = function () {
|
|
42
96
|
if (window.AgentSGTWidgetLoader) {
|
|
43
|
-
AgentSGTWidgetLoader.load(
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
97
|
+
AgentSGTWidgetLoader.load('agent-widget', {
|
|
98
|
+
runtimeUrl: 'https://agentsgt.com/api/v1/agents/chat/YOUR_AGENT_ID',
|
|
99
|
+
apiKey: 'pk_xxx:sk_xxx',
|
|
100
|
+
name: 'My Assistant',
|
|
101
|
+
uiMode: 'popup',
|
|
102
|
+
theme: { primaryColor: '#FBB76B' },
|
|
47
103
|
});
|
|
48
104
|
}
|
|
49
105
|
};
|
|
50
106
|
</script>
|
|
51
|
-
<script src="https://unpkg.com/@agentsgt
|
|
52
|
-
<link
|
|
53
|
-
rel="stylesheet"
|
|
54
|
-
href="https://unpkg.com/@agentsgt/widget/dist/style.css"
|
|
55
|
-
/>
|
|
107
|
+
<script src="https://unpkg.com/@ddrinnova/agentsgt-widget/dist/loader.umd.js"></script>
|
|
56
108
|
```
|
|
57
109
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
| Option | Type | Description |
|
|
61
|
-
| ---------------- | ------ | --------------------------------------------------------------|
|
|
62
|
-
| `title` | string | The title displayed in the widget header |
|
|
63
|
-
| `initialMessage` | string | The first message displayed in the chat |
|
|
64
|
-
| `runtimeUrl` | string | URL to your backend API endpoint (required) |
|
|
65
|
-
| `properties` | json | Additional configuration properties for the widget |
|
|
66
|
-
| `actions` | array | Available actions or functions that the assistant can perform |
|
|
67
|
-
|
|
68
|
-
### Examples
|
|
69
|
-
|
|
70
|
-
#### Properties Example
|
|
71
|
-
|
|
72
|
-
```javascript
|
|
73
|
-
const properties = {
|
|
74
|
-
user: {
|
|
75
|
-
value: "John",
|
|
76
|
-
description: "name of the user"
|
|
77
|
-
},
|
|
78
|
-
pokemones: {
|
|
79
|
-
value: pokemonList, // Imagine an array of JSON objects, each representing a pokemon with properties like "name" and "url"
|
|
80
|
-
description: "available pokemon resources that the assistant can reference"
|
|
81
|
-
},
|
|
82
|
-
instructions: {
|
|
83
|
-
value: "You are an assistant that knows about pokemon and the user's name. Always refer to the user by their name.",
|
|
84
|
-
description: "instructions for the assistant behavior"
|
|
85
|
-
}
|
|
86
|
-
};
|
|
87
|
-
```
|
|
110
|
+
---
|
|
88
111
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
```javascript
|
|
92
|
-
const actions = [
|
|
93
|
-
{
|
|
94
|
-
name: "openUrl",
|
|
95
|
-
description: "Open a URL in a new tab",
|
|
96
|
-
parameters: [
|
|
97
|
-
{ name: "url", type: "string", description: "The URL to open" }
|
|
98
|
-
],
|
|
99
|
-
handler: ({ url }) => {
|
|
100
|
-
window.open(url, "_blank");
|
|
101
|
-
}
|
|
102
|
-
},
|
|
103
|
-
{
|
|
104
|
-
name: "searchPokemon",
|
|
105
|
-
description: "Search for a specific pokemon",
|
|
106
|
-
parameters: [
|
|
107
|
-
{ name: "name", type: "string", description: "Pokemon name to search" }
|
|
108
|
-
],
|
|
109
|
-
handler: ({ name }) => {
|
|
110
|
-
// Custom logic to search pokemon
|
|
111
|
-
console.log(`Searching for pokemon: ${name}`);
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
];
|
|
115
|
-
```
|
|
112
|
+
## Options
|
|
116
113
|
|
|
117
|
-
|
|
114
|
+
| Option | Type | Default | Description |
|
|
115
|
+
|:---|:---|:---|:---|
|
|
116
|
+
| **`runtimeUrl`** | `string` | *required* | Full URL to the agent chat endpoint |
|
|
117
|
+
| **`apiKey`** | `string` | *required* | API key in `pk_xxx:sk_xxx` format |
|
|
118
|
+
| `uiMode` | `"popup"` \| `"sidebar"` \| `"chat"` | `"popup"` | Display mode |
|
|
119
|
+
| `title` | `string` | Agent name | Header title |
|
|
120
|
+
| `initialMessage` | `string` | `"Need any help?"` | Greeting shown on first visit |
|
|
121
|
+
| `identifier` | `string` | — | External user ID for conversation tracking |
|
|
122
|
+
| `theme.primaryColor` | `string` | `#FBB76B` | Accent color |
|
|
118
123
|
|
|
119
|
-
|
|
124
|
+
---
|
|
120
125
|
|
|
121
|
-
##
|
|
126
|
+
## Display Modes
|
|
122
127
|
|
|
123
|
-
|
|
128
|
+
### `"popup"` *(default)*
|
|
129
|
+
Floating chat bubble in the bottom-right corner. Click to open a 400 × 520 chat window. Best for **customer support overlays**.
|
|
124
130
|
|
|
125
|
-
|
|
131
|
+
### `"sidebar"`
|
|
132
|
+
Full-height panel that slides in from the right. Great for **dashboards and admin panels**.
|
|
126
133
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
```
|
|
134
|
+
### `"chat"`
|
|
135
|
+
Inline chat that fills its parent container. Use when **embedding directly into your page layout**.
|
|
130
136
|
|
|
131
|
-
|
|
137
|
+
---
|
|
132
138
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
139
|
+
## Theming
|
|
140
|
+
|
|
141
|
+
### Quick — via prop
|
|
142
|
+
|
|
143
|
+
```js
|
|
144
|
+
{ theme: { primaryColor: '#7C3AED' } }
|
|
136
145
|
```
|
|
137
146
|
|
|
138
|
-
|
|
147
|
+
### Full control — via CSS custom properties
|
|
148
|
+
|
|
149
|
+
```css
|
|
150
|
+
:root {
|
|
151
|
+
--agt-primary: #FBB76B; /* Accent color */
|
|
152
|
+
--agt-bg: #ffffff; /* Widget background */
|
|
153
|
+
--agt-text: #1f2937; /* Primary text */
|
|
154
|
+
--agt-text-secondary: #6b7280; /* Muted text */
|
|
155
|
+
--agt-border: #e5e7eb; /* Borders */
|
|
156
|
+
--agt-muted: #f3f4f6; /* Subtle backgrounds */
|
|
157
|
+
--agt-user-bg: rgba(251, 183, 107, 0.1); /* User bubble */
|
|
158
|
+
--agt-assistant-bg: #f3f4f6; /* Assistant bubble */
|
|
159
|
+
--agt-radius: 1rem; /* Border radius */
|
|
160
|
+
}
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
## API Keys
|
|
166
|
+
|
|
167
|
+
1. Open the [AgentsGT dashboard](https://agentsgt.com)
|
|
168
|
+
2. Navigate to **Settings → API Keys**
|
|
169
|
+
3. Create a new key pair — you'll get a `pk_xxx:sk_xxx` string
|
|
170
|
+
4. Pass it as the `apiKey` prop
|
|
139
171
|
|
|
140
|
-
|
|
172
|
+
> API keys used in client-side widgets are visible to end users. Enable **domain whitelisting** in your dashboard to restrict usage to your domains.
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
## Development
|
|
141
177
|
|
|
142
178
|
```bash
|
|
143
|
-
|
|
179
|
+
git clone https://github.com/ddrinnova/agentsgt-widget.git
|
|
180
|
+
cd agentsgt-widget
|
|
181
|
+
npm install
|
|
182
|
+
npm run dev # Start dev server at localhost:5173
|
|
183
|
+
npm run build # Production build → dist/
|
|
184
|
+
npm run release # Bump patch version + publish to npm
|
|
185
|
+
npm run release:minor # Bump minor version + publish
|
|
186
|
+
npm run release:quick # Bump + publish without git tag
|
|
144
187
|
```
|
|
145
188
|
|
|
146
|
-
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
<div align="center">
|
|
192
|
+
|
|
193
|
+
**Built with [Vercel AI SDK](https://sdk.vercel.ai) + React**
|
|
194
|
+
|
|
195
|
+
[agentsgt.com](https://agentsgt.com) • [GitHub](https://github.com/ddrinnova/agentsgt-widget) • [npm](https://www.npmjs.com/package/@ddrinnova/agentsgt-widget)
|
|
147
196
|
|
|
148
|
-
|
|
197
|
+
</div>
|
package/dist/widget.css
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
:root{--agt-primary: #FBB76B;--agt-bg: #ffffff;--agt-text: #1f2937;--agt-text-secondary: #6b7280;--agt-border: #e5e7eb;--agt-muted: #f3f4f6;--agt-user-bg: rgba(251, 183, 107, .1);--agt-assistant-bg: #f3f4f6;--agt-error-bg: #fef2f2;--agt-error-text: #b91c1c;--agt-radius: 1rem;--agt-shadow: 0 10px 25px -5px rgba(0, 0, 0, .1), 0 8px 10px -6px rgba(0, 0, 0, .1)}.agt-widget,.agt-popup,.agt-sidebar,.agt-trigger{box-sizing:border-box;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.agt-widget *,.agt-popup *,.agt-sidebar *,.agt-trigger *{box-sizing:border-box}.agt-widget{display:flex;flex-direction:column;height:100%;width:100%;overflow:hidden;background:var(--agt-bg);color:var(--agt-text);font-size:14px;line-height:1.5}.agt-popup{position:fixed;bottom:24px;right:24px;z-index:9999;width:400px;height:520px;border-radius:var(--agt-radius);box-shadow:var(--agt-shadow);background:var(--agt-bg);border:1px solid var(--agt-border);display:flex;flex-direction:column;overflow:hidden;animation:agt-slide-up .3s ease-out}@media (max-width: 480px){.agt-popup{bottom:0;right:0;width:100%;height:100%;border-radius:0}}.agt-sidebar{position:fixed;top:0;right:0;z-index:9999;width:380px;height:100%;background:var(--agt-bg);border-left:1px solid var(--agt-border);box-shadow:-4px 0 16px #00000014;display:flex;flex-direction:column;animation:agt-slide-in-right .3s ease-out}@media (max-width: 480px){.agt-sidebar{width:100%}}.agt-trigger{position:fixed;bottom:24px;right:24px;z-index:9998;width:56px;height:56px;border-radius:50%;background:var(--agt-primary);color:#fff;border:none;cursor:pointer;display:flex;align-items:center;justify-content:center;box-shadow:0 4px 12px #00000026;transition:transform .2s ease,box-shadow .2s ease;animation:agt-scale-in .3s ease-out}.agt-trigger:hover{transform:scale(1.08);box-shadow:0 6px 16px #0003}.agt-header{display:flex;align-items:center;justify-content:space-between;padding:12px 16px;border-bottom:1px solid var(--agt-border);background:var(--agt-bg);flex-shrink:0}.agt-header__title{font-weight:600;font-size:14px;color:var(--agt-text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.agt-header__actions{display:flex;align-items:center;gap:4px}.agt-header__btn{display:flex;align-items:center;justify-content:center;width:28px;height:28px;border:none;background:transparent;border-radius:6px;cursor:pointer;color:var(--agt-text-secondary);transition:background-color .15s,color .15s}.agt-header__btn:hover{background:var(--agt-muted);color:var(--agt-text)}.agt-footer{padding:6px 16px;text-align:center;font-size:10px;color:var(--agt-text-secondary);border-top:1px solid var(--agt-border);flex-shrink:0}.agt-messages{flex:1;overflow-y:auto;padding:16px}.agt-messages__inner{display:flex;flex-direction:column;gap:12px}.agt-message{display:flex;width:100%}.agt-message--user{justify-content:flex-end}.agt-message--assistant{justify-content:flex-start}.agt-message__content{max-width:78%;border-radius:var(--agt-radius);padding:8px 12px;font-size:14px;line-height:1.5;word-break:break-word}.agt-message--user .agt-message__content{background:var(--agt-user-bg);color:var(--agt-text);border-bottom-right-radius:4px}.agt-message--assistant .agt-message__content{background:var(--agt-assistant-bg);color:var(--agt-text);border-bottom-left-radius:4px}.agt-message__content--error{background:var(--agt-error-bg)!important;color:var(--agt-error-text)!important;display:flex;align-items:flex-start;gap:8px;border:1px solid rgba(185,28,28,.15)}.agt-message__typing{display:flex;align-items:center;gap:4px;padding:4px 0}.agt-message__typing span{width:6px;height:6px;border-radius:50%;background:var(--agt-text-secondary);animation:agt-bounce 1.4s infinite ease-in-out both}.agt-message__typing span:nth-child(1){animation-delay:-.32s}.agt-message__typing span:nth-child(2){animation-delay:-.16s}.agt-input{padding:8px 16px 12px;flex-shrink:0}.agt-input__container{display:flex;align-items:flex-end;gap:8px;border:1px solid var(--agt-border);border-radius:var(--agt-radius);padding:8px 12px;background:var(--agt-bg);transition:border-color .15s}.agt-input__container:focus-within{border-color:var(--agt-primary)}.agt-input__textarea{flex:1;border:none;outline:none;background:transparent;font-size:14px;font-family:inherit;color:var(--agt-text);line-height:1.5;min-height:24px;padding:0}.agt-input__textarea::-moz-placeholder{color:var(--agt-text-secondary);opacity:.6}.agt-input__textarea::placeholder{color:var(--agt-text-secondary);opacity:.6}.agt-input__send{display:flex;align-items:center;justify-content:center;width:28px;height:28px;border:none;border-radius:50%;background:var(--agt-text);color:var(--agt-bg);cursor:pointer;flex-shrink:0;transition:opacity .15s}.agt-input__send:disabled{opacity:.3;cursor:default}.agt-input__send:not(:disabled):hover{opacity:.8}.agt-tool{display:flex;align-items:center;gap:8px;padding:8px 12px;background:var(--agt-muted);border-radius:8px;margin:8px 0;font-size:13px;color:var(--agt-text-secondary)}.agt-tool--error{background:var(--agt-error-bg);color:var(--agt-error-text)}.agt-tool--sources{padding:6px 10px;font-size:13px;margin:6px 0;background:#00000008;border:1px solid rgba(0,0,0,.06);border-radius:8px}.agt-tool__label{color:var(--agt-text-secondary);font-weight:500;margin-right:4px}.agt-tool--sources a{color:var(--agt-primary);text-decoration:none}.agt-tool--sources a:hover{text-decoration:underline}.agt-tool__separator{color:var(--agt-text-secondary);margin:0 6px}.agt-tool__image{margin:8px 0}.agt-tool__image img{border-radius:8px;max-width:100%;max-height:300px;-o-object-fit:contain;object-fit:contain}.agt-spinner{display:inline-flex;align-items:center;gap:4px}.agt-spinner__dot{width:6px;height:6px;border-radius:50%;background:var(--agt-text-secondary);animation:agt-bounce 1.4s infinite ease-in-out both}.agt-spinner__dot:nth-child(1){animation-delay:-.32s}.agt-spinner__dot:nth-child(2){animation-delay:-.16s}.agt-markdown p{margin:.25em 0;line-height:1.6}.agt-markdown p:first-child{margin-top:0}.agt-markdown p:last-child{margin-bottom:0}.agt-markdown strong{font-weight:600}.agt-markdown em{font-style:italic}.agt-markdown code{background:#0000000f;padding:.1em .35em;border-radius:4px;font-size:.85em;font-family:SF Mono,Monaco,Cascadia Code,monospace}.agt-markdown pre{background:#0000000f;padding:12px;border-radius:8px;overflow-x:auto;margin:8px 0;font-size:13px}.agt-markdown pre code{background:none;padding:0;border-radius:0;font-size:inherit}.agt-markdown ul{list-style:disc;padding-left:1.25em;margin:.25em 0}.agt-markdown ol{list-style:decimal;padding-left:1.25em;margin:.25em 0}.agt-markdown li{margin:.1em 0}.agt-markdown a{color:var(--agt-primary);text-decoration:underline;text-decoration-color:#fbb76b66;text-underline-offset:2px}.agt-markdown a:hover{text-decoration-color:var(--agt-primary)}.agt-markdown table{width:100%;border-collapse:collapse;margin:8px 0;font-size:13px}.agt-markdown th,.agt-markdown td{padding:6px 10px;border:1px solid var(--agt-border);text-align:left}.agt-markdown th{background:var(--agt-muted);font-weight:600;font-size:12px;color:var(--agt-text-secondary)}.agt-markdown hr{border:none;border-top:1px solid var(--agt-border);margin:12px 0}.agt-markdown blockquote{border-left:3px solid var(--agt-border);margin:8px 0;padding:4px 12px;color:var(--agt-text-secondary)}@keyframes agt-slide-up{0%{opacity:0;transform:translateY(12px)}to{opacity:1;transform:translateY(0)}}@keyframes agt-slide-in-right{0%{transform:translate(100%)}to{transform:translate(0)}}@keyframes agt-scale-in{0%{opacity:0;transform:scale(.8)}to{opacity:1;transform:scale(1)}}@keyframes agt-bounce{0%,80%,to{transform:scale(0)}40%{transform:scale(1)}}.agt-messages::-webkit-scrollbar{width:6px}.agt-messages::-webkit-scrollbar-track{background:transparent}.agt-messages::-webkit-scrollbar-thumb{background:#00000026;border-radius:3px}.agt-messages::-webkit-scrollbar-thumb:hover{background:#00000040}
|