@matdata/yasgui 5.0.1 → 5.2.0

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.
Files changed (38) hide show
  1. package/README.md +196 -111
  2. package/build/ts/src/PersistentConfig.d.ts +4 -1
  3. package/build/ts/src/PersistentConfig.js +8 -0
  4. package/build/ts/src/PersistentConfig.js.map +1 -1
  5. package/build/ts/src/Tab.d.ts +8 -0
  6. package/build/ts/src/Tab.js +85 -1
  7. package/build/ts/src/Tab.js.map +1 -1
  8. package/build/ts/src/TabElements.js +6 -0
  9. package/build/ts/src/TabElements.js.map +1 -1
  10. package/build/ts/src/TabSettingsModal.d.ts +4 -0
  11. package/build/ts/src/TabSettingsModal.js +128 -9
  12. package/build/ts/src/TabSettingsModal.js.map +1 -1
  13. package/build/ts/src/ThemeManager.d.ts +17 -0
  14. package/build/ts/src/ThemeManager.js +69 -0
  15. package/build/ts/src/ThemeManager.js.map +1 -0
  16. package/build/ts/src/defaults.js +4 -0
  17. package/build/ts/src/defaults.js.map +1 -1
  18. package/build/ts/src/index.d.ts +16 -0
  19. package/build/ts/src/index.js +17 -0
  20. package/build/ts/src/index.js.map +1 -1
  21. package/build/yasgui.min.css +1 -1
  22. package/build/yasgui.min.css.map +3 -3
  23. package/build/yasgui.min.js +114 -98
  24. package/build/yasgui.min.js.map +4 -4
  25. package/package.json +1 -1
  26. package/src/PersistentConfig.ts +10 -1
  27. package/src/Tab.ts +125 -0
  28. package/src/TabElements.scss +33 -6
  29. package/src/TabElements.ts +9 -0
  30. package/src/TabSettingsModal.scss +154 -20
  31. package/src/TabSettingsModal.ts +171 -13
  32. package/src/ThemeManager.ts +120 -0
  33. package/src/defaults.ts +4 -0
  34. package/src/endpointSelect.scss +34 -0
  35. package/src/index.scss +2 -2
  36. package/src/index.ts +43 -0
  37. package/src/tab.scss +60 -8
  38. package/src/themes.scss +543 -0
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@matdata/yasgui",
3
3
  "description": "Yet Another SPARQL GUI",
4
- "version": "5.0.1",
4
+ "version": "5.2.0",
5
5
  "main": "build/yasgui.min.js",
6
6
  "types": "build/ts/src/index.d.ts",
7
7
  "license": "MIT",
@@ -1,5 +1,5 @@
1
1
  import { Storage as YStorage } from "@matdata/yasgui-utils";
2
- import Yasgui from "./";
2
+ import Yasgui, { EndpointButton } from "./";
3
3
  import * as Tab from "./Tab";
4
4
  export var storageNamespace = "triply";
5
5
  export interface PersistedJson {
@@ -10,6 +10,7 @@ export interface PersistedJson {
10
10
  lastClosedTab: { index: number; tab: Tab.PersistedJson } | undefined;
11
11
  prefixes?: string;
12
12
  autoCaptureEnabled?: boolean;
13
+ customEndpointButtons?: EndpointButton[];
13
14
  }
14
15
  function getDefaults(): PersistedJson {
15
16
  return {
@@ -20,6 +21,7 @@ function getDefaults(): PersistedJson {
20
21
  lastClosedTab: undefined,
21
22
  prefixes: "",
22
23
  autoCaptureEnabled: true,
24
+ customEndpointButtons: [],
23
25
  };
24
26
  }
25
27
 
@@ -152,6 +154,13 @@ export default class PersistentConfig {
152
154
  this.persistedJson.autoCaptureEnabled = enabled;
153
155
  this.toStorage();
154
156
  }
157
+ public getCustomEndpointButtons(): EndpointButton[] {
158
+ return this.persistedJson.customEndpointButtons || [];
159
+ }
160
+ public setCustomEndpointButtons(buttons: EndpointButton[]) {
161
+ this.persistedJson.customEndpointButtons = buttons;
162
+ this.toStorage();
163
+ }
155
164
  public static clear() {
156
165
  const storage = new YStorage(storageNamespace);
157
166
  storage.removeNamespace();
package/src/Tab.ts CHANGED
@@ -9,6 +9,17 @@ import * as shareLink from "./linkUtils";
9
9
  import EndpointSelect from "./endpointSelect";
10
10
  import "./tab.scss";
11
11
  import { getRandomId, default as Yasgui, YasguiRequestConfig } from "./";
12
+
13
+ // Layout orientation toggle icons
14
+ const HORIZONTAL_LAYOUT_ICON = `<svg viewBox="0 0 24 24" class="svgImg">
15
+ <rect x="2" y="4" width="9" height="16" stroke="currentColor" stroke-width="2" fill="none"/>
16
+ <rect x="13" y="4" width="9" height="16" stroke="currentColor" stroke-width="2" fill="none"/>
17
+ </svg>`;
18
+
19
+ const VERTICAL_LAYOUT_ICON = `<svg viewBox="0 0 24 24" class="svgImg">
20
+ <rect x="2" y="2" width="20" height="8" stroke="currentColor" stroke-width="2" fill="none"/>
21
+ <rect x="2" y="12" width="20" height="10" stroke="currentColor" stroke-width="2" fill="none"/>
22
+ </svg>`;
12
23
  export interface PersistedJsonYasr extends YasrPersistentConfig {
13
24
  responseSummary: Parser.ResponseSummary;
14
25
  }
@@ -57,12 +68,16 @@ export class Tab extends EventEmitter {
57
68
  private yasqeWrapperEl: HTMLDivElement | undefined;
58
69
  private yasrWrapperEl: HTMLDivElement | undefined;
59
70
  private endpointSelect: EndpointSelect | undefined;
71
+ private endpointButtonsContainer: HTMLDivElement | undefined;
60
72
  private settingsModal?: TabSettingsModal;
73
+ private currentOrientation: "vertical" | "horizontal";
74
+ private orientationToggleButton?: HTMLButtonElement;
61
75
  constructor(yasgui: Yasgui, conf: PersistedJson) {
62
76
  super();
63
77
  if (!conf || conf.id === undefined) throw new Error("Expected a valid configuration to initialize tab with");
64
78
  this.yasgui = yasgui;
65
79
  this.persistentJson = conf;
80
+ this.currentOrientation = this.yasgui.config.orientation || "vertical";
66
81
  }
67
82
  public name() {
68
83
  return this.persistentJson.name;
@@ -81,6 +96,9 @@ export class Tab extends EventEmitter {
81
96
  this.rootEl.setAttribute("role", "tabpanel");
82
97
  this.rootEl.setAttribute("aria-labelledby", "tab-" + this.persistentJson.id);
83
98
 
99
+ // Apply orientation class
100
+ addClass(this.rootEl, `orientation-${this.currentOrientation}`);
101
+
84
102
  // We group controlbar and Yasqe, so that users can easily .appendChild() to the .editorwrapper div
85
103
  // to add a div that goes alongside the controlbar and editor, while YASR still goes full width
86
104
  // Useful for adding an infos div that goes alongside the editor without needing to rebuild the whole Yasgui class
@@ -99,6 +117,7 @@ export class Tab extends EventEmitter {
99
117
 
100
118
  //yasr
101
119
  this.yasrWrapperEl = document.createElement("div");
120
+ this.yasrWrapperEl.className = "yasrWrapperEl";
102
121
 
103
122
  this.initTabSettingsMenu();
104
123
  this.rootEl.appendChild(editorWrapper);
@@ -222,10 +241,63 @@ export class Tab extends EventEmitter {
222
241
  }
223
242
  private initControlbar() {
224
243
  this.initEndpointSelectField();
244
+ this.initOrientationToggle();
245
+ this.initEndpointButtons();
225
246
  if (this.yasgui.config.endpointInfo && this.controlBarEl) {
226
247
  this.controlBarEl.appendChild(this.yasgui.config.endpointInfo());
227
248
  }
228
249
  }
250
+
251
+ private initOrientationToggle() {
252
+ if (!this.controlBarEl) return;
253
+
254
+ this.orientationToggleButton = document.createElement("button");
255
+ this.orientationToggleButton.className = "tabContextButton orientationToggle";
256
+ this.orientationToggleButton.setAttribute("aria-label", "Toggle layout orientation");
257
+ this.orientationToggleButton.title = "Toggle layout orientation";
258
+
259
+ this.updateOrientationToggleIcon();
260
+
261
+ this.orientationToggleButton.addEventListener("click", () => {
262
+ this.toggleOrientation();
263
+ });
264
+
265
+ this.controlBarEl.appendChild(this.orientationToggleButton);
266
+ }
267
+
268
+ private updateOrientationToggleIcon() {
269
+ if (!this.orientationToggleButton) return;
270
+
271
+ // Show the icon for the layout we'll switch TO (not the current layout)
272
+ this.orientationToggleButton.innerHTML =
273
+ this.currentOrientation === "vertical" ? HORIZONTAL_LAYOUT_ICON : VERTICAL_LAYOUT_ICON;
274
+ this.orientationToggleButton.title =
275
+ this.currentOrientation === "vertical" ? "Switch to horizontal layout" : "Switch to vertical layout";
276
+ }
277
+
278
+ public toggleOrientation() {
279
+ if (!this.rootEl) return;
280
+
281
+ // Remove old orientation class
282
+ removeClass(this.rootEl, `orientation-${this.currentOrientation}`);
283
+
284
+ // Toggle orientation
285
+ this.currentOrientation = this.currentOrientation === "vertical" ? "horizontal" : "vertical";
286
+
287
+ // Add new orientation class
288
+ addClass(this.rootEl, `orientation-${this.currentOrientation}`);
289
+
290
+ // Update button icon
291
+ this.updateOrientationToggleIcon();
292
+
293
+ // Refresh components to adjust to new layout
294
+ if (this.yasqe) {
295
+ this.yasqe.refresh();
296
+ }
297
+ if (this.yasr) {
298
+ this.yasr.refresh();
299
+ }
300
+ }
229
301
  public getYasqe() {
230
302
  return this.yasqe;
231
303
  }
@@ -253,6 +325,54 @@ export class Tab extends EventEmitter {
253
325
  });
254
326
  }
255
327
 
328
+ private initEndpointButtons() {
329
+ if (!this.controlBarEl) throw new Error("Need to initialize wrapper elements before drawing endpoint buttons");
330
+
331
+ // Create container if it doesn't exist
332
+ if (!this.endpointButtonsContainer) {
333
+ this.endpointButtonsContainer = document.createElement("div");
334
+ addClass(this.endpointButtonsContainer, "endpointButtonsContainer");
335
+ this.controlBarEl.appendChild(this.endpointButtonsContainer);
336
+ }
337
+
338
+ this.refreshEndpointButtons();
339
+ }
340
+
341
+ public refreshEndpointButtons() {
342
+ if (!this.endpointButtonsContainer) return;
343
+
344
+ // Clear existing buttons
345
+ this.endpointButtonsContainer.innerHTML = "";
346
+
347
+ // Merge config buttons with custom user buttons
348
+ const configButtons = this.yasgui.config.endpointButtons || [];
349
+ const customButtons = this.yasgui.persistentConfig.getCustomEndpointButtons();
350
+ const allButtons = [...configButtons, ...customButtons];
351
+
352
+ if (allButtons.length === 0) {
353
+ // Hide container if no buttons
354
+ this.endpointButtonsContainer.style.display = "none";
355
+ return;
356
+ }
357
+
358
+ // Show container
359
+ this.endpointButtonsContainer.style.display = "flex";
360
+
361
+ allButtons.forEach((buttonConfig) => {
362
+ const button = document.createElement("button");
363
+ addClass(button, "endpointButton");
364
+ button.textContent = buttonConfig.label;
365
+ button.title = `Set endpoint to ${buttonConfig.endpoint}`;
366
+ button.setAttribute("aria-label", `Set endpoint to ${buttonConfig.endpoint}`);
367
+
368
+ button.addEventListener("click", () => {
369
+ this.setEndpoint(buttonConfig.endpoint);
370
+ });
371
+
372
+ this.endpointButtonsContainer!.appendChild(button);
373
+ });
374
+ }
375
+
256
376
  private checkEndpointForCors(endpoint: string) {
257
377
  if (this.yasgui.config.corsProxy && !(endpoint in Yasgui.corsEnabled)) {
258
378
  const askUrl = new URL(endpoint);
@@ -356,8 +476,13 @@ export class Tab extends EventEmitter {
356
476
  }
357
477
 
358
478
  private initYasqe() {
479
+ // Set theme based on current yasgui theme
480
+ const currentTheme = this.yasgui.getTheme();
481
+ const cmTheme = currentTheme === "dark" ? "material-palenight" : "default";
482
+
359
483
  const yasqeConf: Partial<YasqeConfig> = {
360
484
  ...this.yasgui.config.yasqe,
485
+ theme: cmTheme,
361
486
  value: this.persistentJson.yasqe.value,
362
487
  editorHeight: this.persistentJson.yasqe.editorHeight ? this.persistentJson.yasqe.editorHeight : undefined,
363
488
  persistenceId: null, //yasgui handles persistent storing
@@ -18,6 +18,33 @@ $minTabHeight: 35px;
18
18
  border-bottom: 2px solid transparent;
19
19
  box-sizing: border-box;
20
20
  }
21
+ .themeToggle {
22
+ cursor: pointer;
23
+ height: 100%;
24
+ margin-left: auto;
25
+ margin-right: 10px;
26
+ padding: 6px 8px;
27
+ background: transparent;
28
+ border: none;
29
+ color: var(--yasgui-button-text, #505050);
30
+ fill: var(--yasgui-button-text, #505050);
31
+ display: flex;
32
+ align-items: center;
33
+ justify-content: center;
34
+ border-radius: 4px;
35
+
36
+ &:hover {
37
+ color: var(--yasgui-button-hover, #000);
38
+ fill: var(--yasgui-button-hover, #000);
39
+ background: var(--yasgui-bg-secondary, #f7f7f7);
40
+ }
41
+
42
+ svg {
43
+ width: 20px;
44
+ height: 20px;
45
+ }
46
+ }
47
+
21
48
  .addTab {
22
49
  cursor: pointer;
23
50
  height: 100%;
@@ -80,7 +107,7 @@ $minTabHeight: 35px;
80
107
  }
81
108
  &.active a {
82
109
  border-bottom-color: $activeColor;
83
- color: #555;
110
+ color: var(--yasgui-text-primary, #555);
84
111
  }
85
112
  input {
86
113
  display: none;
@@ -100,7 +127,7 @@ $minTabHeight: 35px;
100
127
  }
101
128
  a {
102
129
  font-weight: 600;
103
- color: color.adjust(#555, $lightness: 20%);
130
+ color: var(--yasgui-text-secondary, color.adjust(#555, $lightness: 20%));
104
131
  font-size: 15px;
105
132
  line-height: 1.5rem;
106
133
  font-weight: 500;
@@ -110,17 +137,17 @@ $minTabHeight: 35px;
110
137
  overflow: hidden;
111
138
  &:hover {
112
139
  border-bottom-color: $hoverColor;
113
- color: #555;
140
+ color: var(--yasgui-text-primary, #555);
114
141
  }
115
142
  &:focus {
116
143
  border-bottom-color: #faa857;
117
- color: #555;
144
+ color: var(--yasgui-text-primary, #555);
118
145
  }
119
146
  .closeTab {
120
- color: #000;
147
+ color: var(--yasgui-text-primary, #000);
121
148
  margin-left: 7px;
122
149
  font-size: 15px;
123
- text-shadow: 0 1px 0 #fff;
150
+ text-shadow: 0 1px 0 var(--yasgui-bg-primary, #fff);
124
151
  opacity: 0.2;
125
152
  font-weight: 700;
126
153
  padding: 2px;
@@ -3,6 +3,15 @@ import TabContextMenu from "./TabContextMenu";
3
3
  import { hasClass, addClass, removeClass } from "@matdata/yasgui-utils";
4
4
  import sortablejs from "sortablejs";
5
5
  import "./TabElements.scss";
6
+
7
+ // Theme toggle icons
8
+ const MOON_ICON = `<svg viewBox="0 0 24 24" fill="currentColor">
9
+ <path d="M12 3c-4.97 0-9 4.03-9 9s4.03 9 9 9 9-4.03 9-9c0-.46-.04-.92-.1-1.36-.98 1.37-2.58 2.26-4.4 2.26-2.98 0-5.4-2.42-5.4-5.4 0-1.81.89-3.42 2.26-4.4-.44-.06-.9-.1-1.36-.1z"/>
10
+ </svg>`;
11
+
12
+ const SUN_ICON = `<svg viewBox="0 0 24 24" fill="currentColor">
13
+ <path d="M12 7c-2.76 0-5 2.24-5 5s2.24 5 5 5 5-2.24 5-5-2.24-5-5-5zM2 13h2c.55 0 1-.45 1-1s-.45-1-1-1H2c-.55 0-1 .45-1 1s.45 1 1 1zm18 0h2c.55 0 1-.45 1-1s-.45-1-1-1h-2c-.55 0-1 .45-1 1s.45 1 1 1zM11 2v2c0 .55.45 1 1 1s1-.45 1-1V2c0-.55-.45-1-1-1s-1 .45-1 1zm0 18v2c0 .55.45 1 1 1s1-.45 1-1v-2c0-.55-.45-1-1-1s-1 .45-1 1zM5.99 4.58c-.39-.39-1.03-.39-1.41 0-.39.39-.39 1.03 0 1.41l1.06 1.06c.39.39 1.03.39 1.41 0s.39-1.03 0-1.41L5.99 4.58zm12.37 12.37c-.39-.39-1.03-.39-1.41 0-.39.39-.39 1.03 0 1.41l1.06 1.06c.39.39 1.03.39 1.41 0 .39-.39.39-1.03 0-1.41l-1.06-1.06zm1.06-10.96c.39-.39.39-1.03 0-1.41-.39-.39-1.03-.39-1.41 0l-1.06 1.06c-.39.39-.39 1.03 0 1.41s1.03.39 1.41 0l1.06-1.06zM7.05 18.36c.39-.39.39-1.03 0-1.41-.39-.39-1.03-.39-1.41 0l-1.06 1.06c-.39.39-.39 1.03 0 1.41s1.03.39 1.41 0l1.06-1.06z"/>
14
+ </svg>`;
6
15
  export interface TabList {}
7
16
  export class TabListEl {
8
17
  private tabList: TabList;
@@ -1,3 +1,28 @@
1
+ .themeToggle {
2
+ cursor: pointer;
3
+ background: transparent;
4
+ color: inherit;
5
+ border: none;
6
+ padding: 6px 8px;
7
+ margin-left: 10px;
8
+ display: flex;
9
+ align-items: center;
10
+ justify-content: center;
11
+
12
+ svg {
13
+ width: 20px;
14
+ height: 20px;
15
+ }
16
+
17
+ &:hover {
18
+ opacity: 0.7;
19
+ }
20
+
21
+ &:active {
22
+ opacity: 0.5;
23
+ }
24
+ }
25
+
1
26
  .tabPrefixButton {
2
27
  cursor: pointer;
3
28
  background: transparent;
@@ -35,7 +60,7 @@
35
60
  }
36
61
 
37
62
  .tabSettingsModal {
38
- background: white;
63
+ background: var(--yasgui-bg-primary, white);
39
64
  border-radius: 8px;
40
65
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
41
66
  max-width: 800px;
@@ -51,12 +76,13 @@
51
76
  justify-content: space-between;
52
77
  align-items: center;
53
78
  padding: 20px;
54
- border-bottom: 1px solid #e0e0e0;
79
+ border-bottom: 1px solid var(--yasgui-border-color, #e0e0e0);
55
80
 
56
81
  h2 {
57
82
  margin: 0;
58
83
  font-size: 20px;
59
84
  font-weight: 600;
85
+ color: var(--yasgui-text-primary, #000);
60
86
  }
61
87
 
62
88
  .closeButton {
@@ -65,13 +91,13 @@
65
91
  font-size: 32px;
66
92
  line-height: 1;
67
93
  cursor: pointer;
68
- color: #666;
94
+ color: var(--yasgui-text-secondary, #666);
69
95
  padding: 0;
70
96
  width: 32px;
71
97
  height: 32px;
72
98
 
73
99
  &:hover {
74
- color: #333;
100
+ color: var(--yasgui-text-primary, #333);
75
101
  }
76
102
  }
77
103
  }
@@ -86,7 +112,7 @@
86
112
  display: flex;
87
113
  gap: 10px;
88
114
  margin-bottom: 20px;
89
- border-bottom: 2px solid #e0e0e0;
115
+ border-bottom: 2px solid var(--yasgui-border-color, #e0e0e0);
90
116
  }
91
117
 
92
118
  .modalTabButton {
@@ -96,18 +122,18 @@
96
122
  font-size: 14px;
97
123
  font-weight: 600;
98
124
  cursor: pointer;
99
- color: #666;
125
+ color: var(--yasgui-text-secondary, #666);
100
126
  border-bottom: 3px solid transparent;
101
127
  margin-bottom: -2px;
102
128
  transition: all 0.2s;
103
129
 
104
130
  &:hover {
105
- color: #337ab7;
131
+ color: var(--yasgui-accent-color, #337ab7);
106
132
  }
107
133
 
108
134
  &.active {
109
- color: #337ab7;
110
- border-bottom-color: #337ab7;
135
+ color: var(--yasgui-accent-color, #337ab7);
136
+ border-bottom-color: var(--yasgui-accent-color, #337ab7);
111
137
  }
112
138
  }
113
139
 
@@ -128,11 +154,12 @@
128
154
  margin-bottom: 8px;
129
155
  font-size: 14px;
130
156
  display: block;
157
+ color: var(--yasgui-text-primary, #000);
131
158
  }
132
159
 
133
160
  .settingsHelp {
134
161
  font-size: 12px;
135
- color: #666;
162
+ color: var(--yasgui-text-secondary, #666);
136
163
  margin-bottom: 10px;
137
164
  font-style: italic;
138
165
  }
@@ -140,13 +167,15 @@
140
167
  .settingsSelect {
141
168
  width: 100%;
142
169
  padding: 8px;
143
- border: 1px solid #ccc;
170
+ border: 1px solid var(--yasgui-input-border, #ccc);
144
171
  border-radius: 4px;
145
172
  font-size: 14px;
173
+ background-color: var(--yasgui-bg-secondary, white);
174
+ color: var(--yasgui-text-primary, #000);
146
175
 
147
176
  &:focus {
148
177
  outline: none;
149
- border-color: #337ab7;
178
+ border-color: var(--yasgui-input-focus, #337ab7);
150
179
  box-shadow: 0 0 0 2px rgba(51, 122, 183, 0.1);
151
180
  }
152
181
  }
@@ -154,17 +183,19 @@
154
183
  .prefixTextarea {
155
184
  width: 100%;
156
185
  padding: 10px;
157
- border: 1px solid #ccc;
186
+ border: 1px solid var(--yasgui-input-border, #ccc);
158
187
  border-radius: 4px;
159
188
  font-family: monospace;
160
189
  font-size: 13px;
161
190
  resize: vertical;
162
191
  box-sizing: border-box;
163
192
  min-height: 200px;
193
+ background-color: var(--yasgui-bg-secondary, white);
194
+ color: var(--yasgui-text-primary, #000);
164
195
 
165
196
  &:focus {
166
197
  outline: none;
167
- border-color: #337ab7;
198
+ border-color: var(--yasgui-input-focus, #337ab7);
168
199
  box-shadow: 0 0 0 2px rgba(51, 122, 183, 0.1);
169
200
  }
170
201
  }
@@ -186,12 +217,13 @@
186
217
  font-size: 14px;
187
218
  user-select: none;
188
219
  margin: 0;
220
+ color: var(--yasgui-text-primary, #000);
189
221
  }
190
222
  }
191
223
 
192
224
  .modalFooter {
193
225
  padding: 15px 20px;
194
- border-top: 1px solid #e0e0e0;
226
+ border-top: 1px solid var(--yasgui-border-color, #e0e0e0);
195
227
  display: flex;
196
228
  justify-content: flex-end;
197
229
  gap: 10px;
@@ -208,19 +240,121 @@
208
240
  }
209
241
 
210
242
  .primaryButton {
211
- background: #337ab7;
243
+ background: var(--yasgui-accent-color, #337ab7);
212
244
  color: white;
213
245
 
214
246
  &:hover {
215
- background: #286090;
247
+ background: var(--yasgui-link-hover, #286090);
216
248
  }
217
249
  }
218
250
 
219
251
  .secondaryButton {
220
- background: #e0e0e0;
221
- color: #333;
252
+ background: var(--yasgui-bg-tertiary, #e0e0e0);
253
+ color: var(--yasgui-text-primary, #333);
222
254
 
223
255
  &:hover {
224
- background: #d0d0d0;
256
+ background: var(--yasgui-border-color, #d0d0d0);
257
+ }
258
+ }
259
+
260
+ .endpointButtonsList {
261
+ margin: 15px 0;
262
+ border: 1px solid var(--yasgui-border-color, #ddd);
263
+ border-radius: 4px;
264
+ padding: 10px;
265
+ background: var(--yasgui-bg-secondary, #f7f7f7);
266
+ max-height: 200px;
267
+ overflow-y: auto;
268
+ }
269
+
270
+ .endpointButtonItem {
271
+ display: flex;
272
+ align-items: center;
273
+ padding: 8px;
274
+ margin-bottom: 8px;
275
+ background: var(--yasgui-bg-primary, #fff);
276
+ border: 1px solid var(--yasgui-border-color, #ddd);
277
+ border-radius: 3px;
278
+
279
+ &:last-child {
280
+ margin-bottom: 0;
281
+ }
282
+
283
+ .buttonLabel {
284
+ font-weight: 600;
285
+ min-width: 100px;
286
+ color: var(--yasgui-text-primary, #333);
287
+ }
288
+
289
+ .buttonEndpoint {
290
+ flex: 1;
291
+ margin-left: 10px;
292
+ color: var(--yasgui-text-secondary, #666);
293
+ font-size: 13px;
294
+ overflow: hidden;
295
+ text-overflow: ellipsis;
296
+ white-space: nowrap;
297
+ }
298
+
299
+ .removeButton {
300
+ margin-left: auto;
301
+ background: transparent;
302
+ border: none;
303
+ color: var(--yasgui-error-color, #d32f2f);
304
+ font-size: 20px;
305
+ cursor: pointer;
306
+ padding: 0 8px;
307
+ line-height: 1;
308
+
309
+ &:hover {
310
+ opacity: 0.7;
311
+ }
312
+ }
313
+ }
314
+
315
+ .emptyMessage {
316
+ color: var(--yasgui-text-muted, #999);
317
+ font-style: italic;
318
+ text-align: center;
319
+ padding: 20px;
320
+ }
321
+
322
+ .addEndpointButtonForm {
323
+ display: flex;
324
+ gap: 8px;
325
+ align-items: center;
326
+
327
+ input {
328
+ flex: 1;
329
+ padding: 8px 12px;
330
+ border: 1px solid var(--yasgui-border-color, #ddd);
331
+ border-radius: 3px;
332
+ background: var(--yasgui-bg-primary, #fff);
333
+ color: var(--yasgui-text-primary, #333);
334
+ font-size: 14px;
335
+
336
+ &:focus {
337
+ outline: none;
338
+ border-color: var(--yasgui-accent-color, #337ab7);
339
+ }
340
+
341
+ &::placeholder {
342
+ color: var(--yasgui-text-muted, #999);
343
+ }
344
+ }
345
+
346
+ .addEndpointButton {
347
+ padding: 8px 16px;
348
+ background: var(--yasgui-accent-color, #337ab7);
349
+ color: white;
350
+ border: none;
351
+ border-radius: 3px;
352
+ cursor: pointer;
353
+ font-size: 14px;
354
+ white-space: nowrap;
355
+
356
+ &:hover {
357
+ background: var(--yasgui-link-hover, #286090);
358
+ }
225
359
  }
226
360
  }