diff --git a/packages/oc-docs/e2e/components/playground.component.ts b/packages/oc-docs/e2e/components/playground.component.ts index 71c3a6f4..75f42bcb 100644 --- a/packages/oc-docs/e2e/components/playground.component.ts +++ b/packages/oc-docs/e2e/components/playground.component.ts @@ -8,6 +8,8 @@ export class PlaygroundComponent extends BaseComponent { readonly keyValueTable = new KeyValueTableComponent(this.page); readonly preRequestScriptEditor = new CodeEditorComponent(this.page, 'scripts-editor-pre-request'); readonly postResponseScriptEditor = new CodeEditorComponent(this.page, 'scripts-editor-post-response'); + readonly bodyEditor = new CodeEditorComponent(this.page, 'body-editor'); + readonly testsEditor = new CodeEditorComponent(this.page, 'tests-editor'); readonly header = this.page.getByTestId('playground-header'); readonly switcher = this.page.getByTestId('playground-dock-switcher'); @@ -94,6 +96,7 @@ export class PlaygroundComponent extends BaseComponent { async openRequest(name: string): Promise { await this.treeItems.filter({ hasText: name }).first().click(); + await this.view.waitFor({ state: 'visible' }); } async openEnvironments(): Promise { diff --git a/packages/oc-docs/e2e/tests/playground/editor-fill-height.spec.ts b/packages/oc-docs/e2e/tests/playground/editor-fill-height.spec.ts new file mode 100644 index 00000000..4e8e4002 --- /dev/null +++ b/packages/oc-docs/e2e/tests/playground/editor-fill-height.spec.ts @@ -0,0 +1,49 @@ +import type { Locator } from '@playwright/test'; +import { test, expect } from '../../playwright'; + +// The Body / Tests / Scripts editors in the request pane opt into `fillHeight`, so they stretch to +// fill the pane and stop ~1rem above its bottom, instead of a short fixed-height box that either +// leaves a large empty area or overflows the pane. We assert the editor's bottom sits just above +// the view's bottom: a fixed-height editor in this dock would overflow (negative gap) or fall well +// short (large gap). +async function expectFillsPane(editor: Locator, view: Locator): Promise { + await expect(editor).toBeVisible(); + const gapBelow = async (): Promise => { + const e = await editor.boundingBox(); + const v = await view.boundingBox(); + if (!e || !v) return Number.NaN; + return Math.round(v.y + v.height - (e.y + e.height)); + }; + // Monaco relays out after the tab becomes active; retry until the gap settles to ~1rem. + await expect.poll(gapBelow, { message: 'editor should fill to ~1rem above the pane bottom' }).toBeLessThanOrEqual(48); + expect(await gapBelow()).toBeGreaterThanOrEqual(4); + + const editorBox = await editor.boundingBox(); + expect(editorBox!.height).toBeGreaterThan(40); +} + +test.describe('Playground request editors fill height', () => { + // A wide viewport keeps the request-pane tabs on one row (no responsive "⋯" overflow), + // so selecting Body/Tests/Scripts is a direct click rather than a flaky dropdown step. + test.use({ viewport: { width: 1600, height: 900 } }); + + test.beforeEach(async ({ playground }) => { + await playground.open('bottom'); + await playground.openRequest('echo json'); + }); + + test('body editor fills the request pane', async ({ playground }) => { + await playground.selectTab('body'); + await expectFillsPane(playground.bodyEditor.root, playground.view); + }); + + test('tests editor fills the request pane', async ({ playground }) => { + await playground.selectTab('tests'); + await expectFillsPane(playground.testsEditor.root, playground.view); + }); + + test('pre-request script editor fills the request pane', async ({ playground }) => { + await playground.selectTab('scripts'); + await expectFillsPane(playground.preRequestScriptEditor.root, playground.view); + }); +}); diff --git a/packages/oc-docs/src/components/Playground/Content/Views/CollectionSettingsView/CollectionSettingsView.tsx b/packages/oc-docs/src/components/Playground/Content/Views/CollectionSettingsView/CollectionSettingsView.tsx index f74d67ce..a743c5cc 100644 --- a/packages/oc-docs/src/components/Playground/Content/Views/CollectionSettingsView/CollectionSettingsView.tsx +++ b/packages/oc-docs/src/components/Playground/Content/Views/CollectionSettingsView/CollectionSettingsView.tsx @@ -1,6 +1,7 @@ import React, { useState } from 'react'; import type { OpenCollection } from '@opencollection/types'; import Tabs from '../../../../../ui/Tabs/Tabs'; +import TitleLabel from '../../../../TitleLabel/TitleLabel'; import { type KeyValueRow } from '../../../../../components/KeyValueTable/KeyValueTable'; import HeadersTab from '../Common/HeadersTab/HeadersTab'; import VariablesTab from '../Common/VariablesTab/VariablesTab'; @@ -154,10 +155,8 @@ const CollectionSettings: React.FC = ({ collection }) = return ( -
-

- {collection.info?.name || 'Collection Settings'} -

+
+ {collection.info?.name || 'Collection Settings'} {version && Version {version}}
diff --git a/packages/oc-docs/src/components/Playground/Content/Views/CollectionSettingsView/StyledWrapper.ts b/packages/oc-docs/src/components/Playground/Content/Views/CollectionSettingsView/StyledWrapper.ts index 7388fde8..282f49f3 100644 --- a/packages/oc-docs/src/components/Playground/Content/Views/CollectionSettingsView/StyledWrapper.ts +++ b/packages/oc-docs/src/components/Playground/Content/Views/CollectionSettingsView/StyledWrapper.ts @@ -4,7 +4,7 @@ export const StyledWrapper = styled.div` height: 100%; display: flex; flex-direction: column; - padding: 0.75rem 1rem; + padding: 1.25rem 1.25rem 0; .collection-settings-header { display: flex; @@ -12,14 +12,6 @@ export const StyledWrapper = styled.div` gap: 0.5rem; } - .collection-settings-title { - color: var(--text-primary); - font-size: 0.875rem; - font-weight: 500; - line-height: 1; - letter-spacing: 0; - } - .collection-settings-version { color: var(--text-tertiary); font-size: 0.75rem; @@ -32,7 +24,6 @@ export const StyledWrapper = styled.div` flex: 1; min-height: 0; overflow-y: auto; - margin-top: 1.25rem; .tabs { gap: 1rem; diff --git a/packages/oc-docs/src/components/Playground/Content/Views/Common/BodyTab.tsx b/packages/oc-docs/src/components/Playground/Content/Views/Common/BodyTab.tsx index 34a2d831..89d11c2f 100644 --- a/packages/oc-docs/src/components/Playground/Content/Views/Common/BodyTab.tsx +++ b/packages/oc-docs/src/components/Playground/Content/Views/Common/BodyTab.tsx @@ -8,12 +8,14 @@ interface BodyTabProps { body: RequestBody; onItemChange: (item: HttpRequest) => void; item: HttpRequest; + fillHeight?: boolean; } export const BodyTab: React.FC = ({ body, onItemChange, - item + item, + fillHeight = false }) => { const handleFormBodyChange = (formData: KeyValueRow[]) => { const updatedBody = { @@ -52,36 +54,39 @@ export const BodyTab: React.FC = ({ }; return ( -
+
{!body ? (
No body content. Select a body type to add content.
) : 'data' in body && typeof body.data === 'string' ? ( - { - if ('data' in body && typeof body.data === 'string') { - onItemChange({ - ...item, - http: { - ...item.http, - body: { ...body, data: value } as typeof body - } - }); +
+ { + if ('data' in body && typeof body.data === 'string') { + onItemChange({ + ...item, + http: { + ...item.http, + body: { ...body, data: value } as typeof body + } + }); + } + }} + language={ + body.type === 'json' + ? 'jsonc' + : body.type === 'xml' + ? 'xml' + : body.type === 'sparql' + ? 'sparql' + : 'text' } - }} - language={ - body.type === 'json' - ? 'jsonc' - : body.type === 'xml' - ? 'xml' - : body.type === 'sparql' - ? 'sparql' - : 'text' - } - height="300px" - /> + height={fillHeight ? '100%' : '300px'} + testId="body-editor" + /> +
) : Array.isArray(body) || (body?.type === 'form-urlencoded' && Array.isArray(body?.data)) ? ( (() => { const formDataArray = Array.isArray(body) ? body : (body?.data || []); diff --git a/packages/oc-docs/src/components/Playground/Content/Views/Common/ScriptsTab/ScriptsTab.tsx b/packages/oc-docs/src/components/Playground/Content/Views/Common/ScriptsTab/ScriptsTab.tsx index 8cbfd435..f89af072 100644 --- a/packages/oc-docs/src/components/Playground/Content/Views/Common/ScriptsTab/ScriptsTab.tsx +++ b/packages/oc-docs/src/components/Playground/Content/Views/Common/ScriptsTab/ScriptsTab.tsx @@ -15,6 +15,7 @@ interface ScriptsTabProps { title?: string; description?: string; showTests?: boolean; + fillHeight?: boolean; } export const ScriptsTab: React.FC = ({ @@ -22,7 +23,8 @@ export const ScriptsTab: React.FC = ({ onScriptChange, title, description, - showTests = true + showTests = true, + fillHeight = false }) => { const [activeScriptTab, setActiveScriptTab] = useState('pre-request'); @@ -39,7 +41,7 @@ export const ScriptsTab: React.FC = ({ value={scripts.preRequest || ''} onChange={(value: string) => onScriptChange('preRequest', value)} language="javascript" - height="300px" + height={fillHeight ? '100%' : '300px'} hintsFor={['req', 'bru']} active={activeScriptTab === 'pre-request'} testId="scripts-editor-pre-request" @@ -54,7 +56,7 @@ export const ScriptsTab: React.FC = ({ value={scripts.postResponse || ''} onChange={(value: string) => onScriptChange('postResponse', value)} language="javascript" - height="300px" + height={fillHeight ? '100%' : '300px'} hintsFor={['req', 'res', 'bru']} active={activeScriptTab === 'post-response'} testId="scripts-editor-post-response" @@ -64,7 +66,7 @@ export const ScriptsTab: React.FC = ({ ]; return ( - + {(Boolean(title) || Boolean(description)) && (
{title && {title}} @@ -72,7 +74,7 @@ export const ScriptsTab: React.FC = ({
)} -
+
void; title?: string; description?: string; + fillHeight?: boolean; } -export const TestsTab: React.FC = ({ scripts, onScriptChange, title, description }) => { +export const TestsTab: React.FC = ({ scripts, onScriptChange, title, description, fillHeight = false }) => { return ( - + {(Boolean(title) || Boolean(description)) && (
{title && {title}} {description && {description}}
)} - onScriptChange('tests', value)} - language="javascript" - height="400px" - hintsFor={['req', 'res', 'bru']} - /> +
+ onScriptChange('tests', value)} + language="javascript" + height={fillHeight ? '100%' : '400px'} + hintsFor={['req', 'res', 'bru']} + testId="tests-editor" + /> +
); }; diff --git a/packages/oc-docs/src/components/Playground/Content/Views/EnvironmentsView/EnvironmentsView.tsx b/packages/oc-docs/src/components/Playground/Content/Views/EnvironmentsView/EnvironmentsView.tsx index 988c9944..089bd820 100644 --- a/packages/oc-docs/src/components/Playground/Content/Views/EnvironmentsView/EnvironmentsView.tsx +++ b/packages/oc-docs/src/components/Playground/Content/Views/EnvironmentsView/EnvironmentsView.tsx @@ -4,6 +4,7 @@ import type { Environment } from '@opencollection/types/config/environments'; import type { Variable } from '@opencollection/types/common/variables'; import KeyValueTable, { KeyValueRow } from '../../../../../components/KeyValueTable/KeyValueTable'; import Tabs from '../../../../../ui/Tabs/Tabs'; +import TitleLabel from '../../../../TitleLabel/TitleLabel'; import { EmptyState } from '../../../../../ui/EmptyState/EmptyState'; import { StyledWrapper } from './StyledWrapper'; import { EnvironmentLabel } from '../../../../EnvironmentLabel/EnvironmentLabel'; @@ -198,7 +199,7 @@ const EnvironmentsView: React.FC = ({ collection, compact return (
-

Environments

+ Environments
diff --git a/packages/oc-docs/src/components/Playground/Content/Views/EnvironmentsView/StyledWrapper.ts b/packages/oc-docs/src/components/Playground/Content/Views/EnvironmentsView/StyledWrapper.ts index 2289cf90..d55bee98 100644 --- a/packages/oc-docs/src/components/Playground/Content/Views/EnvironmentsView/StyledWrapper.ts +++ b/packages/oc-docs/src/components/Playground/Content/Views/EnvironmentsView/StyledWrapper.ts @@ -9,17 +9,10 @@ export const StyledWrapper = styled.div` background-color: var(--oc-background-base); .env-header { - padding: 1rem 1.5rem 0; + padding: 1.25rem 1.25rem 0; flex-shrink: 0; } - .env-title { - font-size: 1.125rem; - font-weight: 600; - font-size: 0.8125rem; - color: var(--oc-text); - } - .env-message { flex: 1; display: flex; @@ -34,7 +27,7 @@ export const StyledWrapper = styled.div` display: flex; flex-wrap: wrap; gap: 0.5rem; - padding: 0.75rem 1.5rem; + padding: 0.5rem 1.25rem 1rem 1.25rem; } .env-pill { @@ -68,7 +61,7 @@ export const StyledWrapper = styled.div` display: flex; flex-direction: column; min-height: 0; - padding: 0 1.5rem 1.5rem; + padding: 0 1.25rem 1.25rem; } .env-tabs-area .tab-content { diff --git a/packages/oc-docs/src/components/Playground/Content/Views/ExampleView/ExampleView.spec.tsx b/packages/oc-docs/src/components/Playground/Content/Views/ExampleView/ExampleView.spec.tsx index 24fec69a..bb3c540f 100644 --- a/packages/oc-docs/src/components/Playground/Content/Views/ExampleView/ExampleView.spec.tsx +++ b/packages/oc-docs/src/components/Playground/Content/Views/ExampleView/ExampleView.spec.tsx @@ -34,11 +34,6 @@ describe('ExampleView', () => { expect(root.querySelector('textarea')).toBeNull(); }); - it('renders the example-name suffix after a named example', () => { - const root = useRenderToDom(); - expect(query(root, '.example-view-name-suffix').text).toContain('/ Example'); - }); - it('shows an empty message when the request has no params, headers or body', () => { const root = useRenderToDom(); const empty = root.querySelector('[data-testid="example-view-request-empty"]'); diff --git a/packages/oc-docs/src/components/Playground/Content/Views/ExampleView/ExampleView.tsx b/packages/oc-docs/src/components/Playground/Content/Views/ExampleView/ExampleView.tsx index 235305c0..b2a6b41c 100644 --- a/packages/oc-docs/src/components/Playground/Content/Views/ExampleView/ExampleView.tsx +++ b/packages/oc-docs/src/components/Playground/Content/Views/ExampleView/ExampleView.tsx @@ -70,10 +70,7 @@ export const ExampleView: React.FC = ({ request, example, orie return (
- - {example.name || 'Example'} - {example.name && / Example} - + {example.name || 'Example'} {description && {description}}
diff --git a/packages/oc-docs/src/components/Playground/Content/Views/ExampleView/StyledWrapper.ts b/packages/oc-docs/src/components/Playground/Content/Views/ExampleView/StyledWrapper.ts index 5329dbd1..84438a81 100644 --- a/packages/oc-docs/src/components/Playground/Content/Views/ExampleView/StyledWrapper.ts +++ b/packages/oc-docs/src/components/Playground/Content/Views/ExampleView/StyledWrapper.ts @@ -6,7 +6,7 @@ export const StyledWrapper = styled.div` display: flex; flex-direction: column; overflow: hidden; - padding: 1rem 1rem 0; + padding: 1.25rem 1.25rem 0; background: var(--bg-primary); .example-view-head { @@ -17,15 +17,11 @@ export const StyledWrapper = styled.div` margin-bottom: 0.75rem; } .example-view-name { - font-size: 0.8125rem; + font-size: var(--oc-font-size-md); + line-height: 1.4; font-weight: 600; color: var(--text-primary); } - .example-view-name-suffix { - margin-left: 0.375rem; - font-weight: 400; - color: var(--text-tertiary); - } .example-view-desc { color: var(--text-secondary); font-size: 0.8125rem; diff --git a/packages/oc-docs/src/components/Playground/Content/Views/FolderSettingsView/FolderSettingsView.tsx b/packages/oc-docs/src/components/Playground/Content/Views/FolderSettingsView/FolderSettingsView.tsx index b8fdca32..81c772a6 100644 --- a/packages/oc-docs/src/components/Playground/Content/Views/FolderSettingsView/FolderSettingsView.tsx +++ b/packages/oc-docs/src/components/Playground/Content/Views/FolderSettingsView/FolderSettingsView.tsx @@ -2,6 +2,7 @@ import React, { useState } from 'react'; import type { Folder } from '@opencollection/types/collection/item'; import type { OpenCollection } from '@opencollection/types'; import Tabs from '../../../../../ui/Tabs/Tabs'; +import TitleLabel from '../../../../TitleLabel/TitleLabel'; import { type KeyValueRow } from '../../../../../components/KeyValueTable/KeyValueTable'; import { rowToVariable } from '../../../../../utils/variableDataType'; import HeadersTab from '../Common/HeadersTab/HeadersTab'; @@ -218,13 +219,9 @@ const FolderSettings: React.FC = ({ folder, onFolderChange return (
-
-

- {getItemName(folder) || 'Folder Settings'} -

-
+ {getItemName(folder) || 'Folder Settings'} -
+
diff --git a/packages/oc-docs/src/components/Playground/Content/Views/PlaygroundView/PlaygroundView.tsx b/packages/oc-docs/src/components/Playground/Content/Views/PlaygroundView/PlaygroundView.tsx index 7c7457d6..2e6c73b0 100644 --- a/packages/oc-docs/src/components/Playground/Content/Views/PlaygroundView/PlaygroundView.tsx +++ b/packages/oc-docs/src/components/Playground/Content/Views/PlaygroundView/PlaygroundView.tsx @@ -104,8 +104,8 @@ const HttpRequestPlaygroundView: React.FC = ({ item, collec return ( -
- {itemName} +
+ {itemName} = ({ item, ...otherProps }) if (isUnsupportedRequest(item)) { return ( = ({ item, onItemChange }) => { body={body} onItemChange={onItemChange} item={item} + fillHeight /> ); @@ -184,6 +185,7 @@ const RequestPane: React.FC = ({ item, onItemChange }) => { onScriptChange={handleScriptChange} showTests={false} description="Pre and post-request scripts that run before and after this request is sent." + fillHeight /> ); @@ -199,6 +201,7 @@ const RequestPane: React.FC = ({ item, onItemChange }) => { ); diff --git a/packages/oc-docs/src/components/Playground/Content/Views/PlaygroundView/RequestPane/StyledWrapper.ts b/packages/oc-docs/src/components/Playground/Content/Views/PlaygroundView/RequestPane/StyledWrapper.ts index 60dd4c1e..5636b600 100644 --- a/packages/oc-docs/src/components/Playground/Content/Views/PlaygroundView/RequestPane/StyledWrapper.ts +++ b/packages/oc-docs/src/components/Playground/Content/Views/PlaygroundView/RequestPane/StyledWrapper.ts @@ -5,6 +5,15 @@ export const StyledWrapper = styled.div` overflow-y: auto; background-color: var(--bg-primary); + .oc-tabs { + height: 100%; + } + + .oc-tabs .tab-panel { + min-height: 0; + overflow-y: auto; + } + .description, .asserts-description { font-size: 0.8125rem; diff --git a/packages/oc-docs/src/components/Playground/PlaygroundBody/StyledWrapper.ts b/packages/oc-docs/src/components/Playground/PlaygroundBody/StyledWrapper.ts index c12e8973..099508cc 100644 --- a/packages/oc-docs/src/components/Playground/PlaygroundBody/StyledWrapper.ts +++ b/packages/oc-docs/src/components/Playground/PlaygroundBody/StyledWrapper.ts @@ -55,6 +55,14 @@ export const StyledWrapper = styled.div` background-color: var(--oc-background-base); } + .view .oc-tabs .tab-panel { + padding-bottom: 1rem; + } + + .view .oc-tabs .oc-tabs .tab-panel { + padding-bottom: 0; + } + .prompt { display: flex; align-items: center; diff --git a/packages/oc-docs/src/components/PrevNext/StyledWrapper.ts b/packages/oc-docs/src/components/PrevNext/StyledWrapper.ts index f0b43daf..ee74e854 100644 --- a/packages/oc-docs/src/components/PrevNext/StyledWrapper.ts +++ b/packages/oc-docs/src/components/PrevNext/StyledWrapper.ts @@ -23,7 +23,7 @@ export const StyledWrapper = styled.nav` width: 100%; max-width: 20rem; min-height: 4.0625rem; - padding: 0.875rem 1.125rem; + padding: 0.5rem; border-radius: 0.375rem; border: 0.0625rem solid var(--oc-border-border0, var(--border-color)); text-decoration: none; @@ -74,7 +74,7 @@ export const StyledWrapper = styled.nav` max-width: 100%; min-width: 0; font-size: 0.8125rem; - line-height: 1.2; + line-height: 1.4; font-weight: 600; color: var(--oc-text); } @@ -98,7 +98,7 @@ export const StyledWrapper = styled.nav` @container docs (max-width: 1024px) { .prevnext-card { min-height: 3.5rem; - padding: 0.625rem 0.875rem; + padding: 0.5rem; } } @@ -108,7 +108,7 @@ export const StyledWrapper = styled.nav` .prevnext-card { min-height: 3rem; - padding: 0.5rem 0.625rem; + padding: 0.5rem; gap: 0.375rem; } .prevnext-label, diff --git a/packages/oc-docs/src/components/TitleLabel/StyledWrapper.ts b/packages/oc-docs/src/components/TitleLabel/StyledWrapper.ts index 7aea371d..0a020abc 100644 --- a/packages/oc-docs/src/components/TitleLabel/StyledWrapper.ts +++ b/packages/oc-docs/src/components/TitleLabel/StyledWrapper.ts @@ -2,9 +2,9 @@ import styled from '@emotion/styled'; export const StyledWrapper = styled.h2` font-family: var(--font-sans); - font-weight: 500; - line-height: 1; - font-size: var(--oc-font-size-base); + font-weight: 600; + line-height: 1.4; + font-size: var(--oc-font-size-md); letter-spacing: 0; color: var(--text-primary); `; diff --git a/packages/oc-docs/src/components/UnsupportedRequest/UnsupportedRequest.tsx b/packages/oc-docs/src/components/UnsupportedRequest/UnsupportedRequest.tsx index 5e29e7df..a21d85c5 100644 --- a/packages/oc-docs/src/components/UnsupportedRequest/UnsupportedRequest.tsx +++ b/packages/oc-docs/src/components/UnsupportedRequest/UnsupportedRequest.tsx @@ -80,7 +80,7 @@ export const UnsupportedRequest: React.FC = ({ {titleVariant === 'label' ? ( - {name} + {name} ) : ( {name} diff --git a/packages/oc-docs/src/styles/index.css b/packages/oc-docs/src/styles/index.css index 9b4b124c..b80b0299 100644 --- a/packages/oc-docs/src/styles/index.css +++ b/packages/oc-docs/src/styles/index.css @@ -818,6 +818,10 @@ tr.themed-row:nth-child(even) { border-radius: 0 6px 6px 0 !important; } +.markdown-documentation blockquote p:last-child { + margin-bottom: 0 !important; +} + .markdown-documentation hr { margin: 1.5em 0 !important; border: none !important;