@matdata/yasgui 5.1.0 → 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.
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.1.0",
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);
@@ -256,3 +256,105 @@
256
256
  background: var(--yasgui-border-color, #d0d0d0);
257
257
  }
258
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
+ }
359
+ }
360
+ }
@@ -126,8 +126,14 @@ export default class TabSettingsModal {
126
126
  addClass(prefixTab, "modalTabButton");
127
127
  prefixTab.onclick = () => this.switchTab("prefix");
128
128
 
129
+ const endpointsTab = document.createElement("button");
130
+ endpointsTab.textContent = "Endpoint Buttons";
131
+ addClass(endpointsTab, "modalTabButton");
132
+ endpointsTab.onclick = () => this.switchTab("endpoints");
133
+
129
134
  tabsContainer.appendChild(requestTab);
130
135
  tabsContainer.appendChild(prefixTab);
136
+ tabsContainer.appendChild(endpointsTab);
131
137
  body.appendChild(tabsContainer);
132
138
 
133
139
  // Tab content containers
@@ -141,8 +147,14 @@ export default class TabSettingsModal {
141
147
  prefixContent.id = "prefix-content";
142
148
  this.drawPrefixSettings(prefixContent);
143
149
 
150
+ const endpointsContent = document.createElement("div");
151
+ addClass(endpointsContent, "modalTabContent");
152
+ endpointsContent.id = "endpoints-content";
153
+ this.drawEndpointButtonsSettings(endpointsContent);
154
+
144
155
  body.appendChild(requestContent);
145
156
  body.appendChild(prefixContent);
157
+ body.appendChild(endpointsContent);
146
158
 
147
159
  this.modalContent.appendChild(body);
148
160
 
@@ -174,7 +186,11 @@ export default class TabSettingsModal {
174
186
  const contents = this.modalContent.querySelectorAll(".modalTabContent");
175
187
 
176
188
  buttons.forEach((btn, index) => {
177
- if ((tabName === "request" && index === 0) || (tabName === "prefix" && index === 1)) {
189
+ if (
190
+ (tabName === "request" && index === 0) ||
191
+ (tabName === "prefix" && index === 1) ||
192
+ (tabName === "endpoints" && index === 2)
193
+ ) {
178
194
  addClass(btn as HTMLElement, "active");
179
195
  } else {
180
196
  removeClass(btn as HTMLElement, "active");
@@ -342,6 +358,9 @@ export default class TabSettingsModal {
342
358
  this.tab.setRequestConfig(updates);
343
359
  }
344
360
 
361
+ // Refresh endpoint buttons to show any changes
362
+ this.tab.refreshEndpointButtons();
363
+
345
364
  this.close();
346
365
  }
347
366
 
@@ -437,6 +456,117 @@ export default class TabSettingsModal {
437
456
  this.tab.yasgui.persistentConfig.setPrefixes(deduplicated);
438
457
  }
439
458
 
459
+ private drawEndpointButtonsSettings(container: HTMLElement) {
460
+ const section = document.createElement("div");
461
+ addClass(section, "settingsSection");
462
+
463
+ const label = document.createElement("label");
464
+ label.textContent = "Custom Endpoint Buttons";
465
+ addClass(label, "settingsLabel");
466
+
467
+ const help = document.createElement("div");
468
+ help.textContent = "Add custom endpoint buttons that will appear next to the endpoint textbox.";
469
+ addClass(help, "settingsHelp");
470
+
471
+ section.appendChild(label);
472
+ section.appendChild(help);
473
+
474
+ // List of existing buttons
475
+ const buttonsList = document.createElement("div");
476
+ addClass(buttonsList, "endpointButtonsList");
477
+ this.renderEndpointButtonsList(buttonsList);
478
+ section.appendChild(buttonsList);
479
+
480
+ // Form to add new button
481
+ const addForm = document.createElement("div");
482
+ addClass(addForm, "addEndpointButtonForm");
483
+
484
+ const labelInput = document.createElement("input");
485
+ labelInput.type = "text";
486
+ labelInput.placeholder = "Button label (e.g., DBpedia)";
487
+ addClass(labelInput, "endpointButtonLabelInput");
488
+
489
+ const endpointInput = document.createElement("input");
490
+ endpointInput.type = "url";
491
+ endpointInput.placeholder = "Endpoint URL (e.g., https://dbpedia.org/sparql)";
492
+ addClass(endpointInput, "endpointButtonEndpointInput");
493
+
494
+ const addButton = document.createElement("button");
495
+ addButton.textContent = "+ Add Button";
496
+ addClass(addButton, "addEndpointButton");
497
+ addButton.type = "button";
498
+ addButton.onclick = () => {
499
+ const labelValue = labelInput.value.trim();
500
+ const endpointValue = endpointInput.value.trim();
501
+
502
+ if (!labelValue || !endpointValue) {
503
+ alert("Please enter both a label and an endpoint URL.");
504
+ return;
505
+ }
506
+
507
+ // Add to persistent config
508
+ const currentButtons = this.tab.yasgui.persistentConfig.getCustomEndpointButtons();
509
+ currentButtons.push({ label: labelValue, endpoint: endpointValue });
510
+ this.tab.yasgui.persistentConfig.setCustomEndpointButtons(currentButtons);
511
+
512
+ // Clear inputs
513
+ labelInput.value = "";
514
+ endpointInput.value = "";
515
+
516
+ // Refresh list
517
+ this.renderEndpointButtonsList(buttonsList);
518
+ };
519
+
520
+ addForm.appendChild(labelInput);
521
+ addForm.appendChild(endpointInput);
522
+ addForm.appendChild(addButton);
523
+ section.appendChild(addForm);
524
+
525
+ container.appendChild(section);
526
+ }
527
+
528
+ private renderEndpointButtonsList(container: HTMLElement) {
529
+ container.innerHTML = "";
530
+ const customButtons = this.tab.yasgui.persistentConfig.getCustomEndpointButtons();
531
+
532
+ if (customButtons.length === 0) {
533
+ const emptyMsg = document.createElement("div");
534
+ emptyMsg.textContent = "No custom buttons yet. Add one below.";
535
+ addClass(emptyMsg, "emptyMessage");
536
+ container.appendChild(emptyMsg);
537
+ return;
538
+ }
539
+
540
+ customButtons.forEach((btn, index) => {
541
+ const item = document.createElement("div");
542
+ addClass(item, "endpointButtonItem");
543
+
544
+ const labelSpan = document.createElement("span");
545
+ labelSpan.textContent = `${btn.label}`;
546
+ addClass(labelSpan, "buttonLabel");
547
+
548
+ const endpointSpan = document.createElement("span");
549
+ endpointSpan.textContent = btn.endpoint;
550
+ addClass(endpointSpan, "buttonEndpoint");
551
+
552
+ const removeBtn = document.createElement("button");
553
+ removeBtn.textContent = "×";
554
+ addClass(removeBtn, "removeButton");
555
+ removeBtn.type = "button";
556
+ removeBtn.onclick = () => {
557
+ const currentButtons = this.tab.yasgui.persistentConfig.getCustomEndpointButtons();
558
+ currentButtons.splice(index, 1);
559
+ this.tab.yasgui.persistentConfig.setCustomEndpointButtons(currentButtons);
560
+ this.renderEndpointButtonsList(container);
561
+ };
562
+
563
+ item.appendChild(labelSpan);
564
+ item.appendChild(endpointSpan);
565
+ item.appendChild(removeBtn);
566
+ container.appendChild(item);
567
+ });
568
+ }
569
+
440
570
  private getThemeToggleIcon(): string {
441
571
  const currentTheme = this.tab.yasgui.getTheme();
442
572
  // In dark mode, show moon icon (clicking will switch to light)
package/src/defaults.ts CHANGED
@@ -30,6 +30,8 @@ export default function initialize(): Config<CatalogueItem> {
30
30
  yasr: Yasr.defaults,
31
31
  theme: undefined,
32
32
  showThemeToggle: true,
33
+ orientation: "vertical",
34
+ endpointButtons: undefined,
33
35
  endpointCatalogueOptions: {
34
36
  getData: () => {
35
37
  return [
@@ -119,4 +119,38 @@
119
119
  opacity: 0.8;
120
120
  }
121
121
  }
122
+
123
+ .endpointButtonsContainer {
124
+ display: flex;
125
+ align-items: center;
126
+ gap: 4px;
127
+ margin-left: 4px;
128
+ }
129
+
130
+ .endpointButton {
131
+ border: 1px solid var(--yasgui-endpoint-button-border, #337ab7);
132
+ background-color: var(--yasgui-endpoint-button-bg, #337ab7);
133
+ color: var(--yasgui-endpoint-button-text, #ffffff);
134
+ border-radius: 3px;
135
+ cursor: pointer;
136
+ padding: 4px 12px;
137
+ font-size: 13px;
138
+ font-weight: 500;
139
+ white-space: nowrap;
140
+ transition: all 0.2s ease;
141
+
142
+ &:hover {
143
+ background-color: var(--yasgui-endpoint-button-hover-bg, #286090);
144
+ border-color: var(--yasgui-endpoint-button-hover-border, #286090);
145
+ }
146
+
147
+ &:active {
148
+ transform: translateY(1px);
149
+ }
150
+
151
+ &:focus {
152
+ outline: 2px solid var(--yasgui-endpoint-button-focus, #5cb3fd);
153
+ outline-offset: 2px;
154
+ }
155
+ }
122
156
  }
package/src/index.scss CHANGED
@@ -11,8 +11,8 @@
11
11
  left: 0;
12
12
  right: 0;
13
13
  z-index: 9999;
14
- background: white;
15
- border-bottom: 1px solid #ddd;
14
+ background: var(--yasgui-bg-primary);
15
+ border-bottom: 1px solid var(--yasgui-border-color);
16
16
  padding: 5px;
17
17
  margin: 0;
18
18
 
package/src/index.ts CHANGED
@@ -31,6 +31,10 @@ if (window) {
31
31
  export type YasguiRequestConfig = Omit<RequestConfig<Yasgui>, "adjustQueryBeforeRequest"> & {
32
32
  adjustQueryBeforeRequest: RequestConfig<Yasqe>["adjustQueryBeforeRequest"];
33
33
  };
34
+ export interface EndpointButton {
35
+ endpoint: string;
36
+ label: string;
37
+ }
34
38
  export interface Config<EndpointObject extends CatalogueItem = CatalogueItem> {
35
39
  /**
36
40
  * Autofocus yasqe on load or tab switch
@@ -41,6 +45,7 @@ export interface Config<EndpointObject extends CatalogueItem = CatalogueItem> {
41
45
  tabName: string;
42
46
  corsProxy: string | undefined;
43
47
  endpointCatalogueOptions: EndpointSelectConfig<EndpointObject>;
48
+ endpointButtons?: EndpointButton[];
44
49
  //The function allows us to modify the config before we pass it on to a tab
45
50
  populateFromUrl: boolean | ((configFromUrl: PersistedTabJson) => PersistedTabJson);
46
51
  autoAddOnInit: boolean;
@@ -55,6 +60,12 @@ export interface Config<EndpointObject extends CatalogueItem = CatalogueItem> {
55
60
  nonSslDomain?: string;
56
61
  theme?: Theme;
57
62
  showThemeToggle?: boolean;
63
+ /**
64
+ * Layout orientation: 'vertical' (default) or 'horizontal' (side-by-side)
65
+ * 'vertical': YASQE on top, YASR below
66
+ * 'horizontal': YASQE on left, YASR on right
67
+ */
68
+ orientation?: "vertical" | "horizontal";
58
69
  }
59
70
  export type PartialConfig = {
60
71
  [P in keyof Config]?: Config[P] extends object ? Partial<Config[P]> : Config[P];
package/src/tab.scss CHANGED
@@ -18,9 +18,57 @@
18
18
  left: 0;
19
19
  right: 0;
20
20
  z-index: 9999;
21
- background: white;
22
- border-bottom: 1px solid #ddd;
21
+ background: var(--yasgui-bg-primary);
22
+ border-bottom: 1px solid var(--yasgui-border-color);
23
23
  padding: 5px;
24
+
25
+ // Hide the layout orientation toggle button in fullscreen mode
26
+ .orientationToggle {
27
+ display: none;
28
+ }
29
+ }
30
+
31
+ // Horizontal layout (side-by-side)
32
+ &.orientation-horizontal {
33
+ &.active {
34
+ display: flex;
35
+ flex-direction: row;
36
+ gap: 10px;
37
+ // Allow flexible height - can use 100vh or be constrained by parent
38
+ min-height: var(--yasgui-min-height);
39
+ height: calc(100vh - var(--yasgui-header-height));
40
+ }
41
+
42
+ .editorwrapper {
43
+ flex: 1;
44
+ min-width: 0;
45
+ display: flex;
46
+ flex-direction: column;
47
+ overflow: hidden;
48
+ }
49
+
50
+ // Make YASQE fill the vertical space in horizontal mode
51
+ .yasqe {
52
+ display: flex;
53
+ flex-direction: column;
54
+ flex: 1;
55
+ min-height: 0;
56
+
57
+ .CodeMirror {
58
+ height: 100% !important;
59
+ }
60
+ }
61
+
62
+ .yasrWrapperEl {
63
+ flex: 1;
64
+ min-width: 0;
65
+ overflow: hidden;
66
+ }
67
+
68
+ .yasr {
69
+ margin-top: 0;
70
+ height: 100%;
71
+ }
24
72
  }
25
73
  }
26
74
  .yasr {
package/src/themes.scss CHANGED
@@ -36,6 +36,18 @@
36
36
  --yasgui-fallback-border: #d1d1d1;
37
37
  --yasgui-resize-handle: #d1d1d1;
38
38
  --yasgui-nav-bg: #eee;
39
+ --yasgui-match-highlight-bg: #dbdeed;
40
+
41
+ // Layout dimensions (used for horizontal orientation)
42
+ --yasgui-header-height: 100px; // Height to subtract from viewport in horizontal layout
43
+ --yasgui-min-height: 400px; // Minimum height for horizontal layout panels
44
+
45
+ --yasgui-endpoint-button-bg: #337ab7;
46
+ --yasgui-endpoint-button-border: #337ab7;
47
+ --yasgui-endpoint-button-text: #ffffff;
48
+ --yasgui-endpoint-button-hover-bg: #286090;
49
+ --yasgui-endpoint-button-hover-border: #286090;
50
+ --yasgui-endpoint-button-focus: #5cb3fd;
39
51
  }
40
52
 
41
53
  [data-theme="dark"] {
@@ -73,6 +85,13 @@
73
85
  --yasgui-fallback-border: #3e3e42;
74
86
  --yasgui-resize-handle: #3e3e42;
75
87
  --yasgui-nav-bg: #2d2d30;
88
+ --yasgui-match-highlight-bg: #3a4a5a;
89
+ --yasgui-endpoint-button-bg: #4fc3f7;
90
+ --yasgui-endpoint-button-border: #4fc3f7;
91
+ --yasgui-endpoint-button-text: #1e1e1e;
92
+ --yasgui-endpoint-button-hover-bg: #81d4fa;
93
+ --yasgui-endpoint-button-hover-border: #81d4fa;
94
+ --yasgui-endpoint-button-focus: #81d4fa;
76
95
  }
77
96
 
78
97
  // Apply theme colors to Yasgui components
@@ -255,6 +274,10 @@
255
274
  fill: var(--yasgui-error-color);
256
275
  }
257
276
 
277
+ .cm-matchhighlight {
278
+ background-color: var(--yasgui-match-highlight-bg);
279
+ }
280
+
258
281
  // Yasqe buttons theming (share, query, fullscreen)
259
282
  .yasqe_buttons {
260
283
  svg {