From 6f92fff15cc3d207f444507a729535ce1c56abd2 Mon Sep 17 00:00:00 2001 From: eeakrnm Date: Wed, 24 Jun 2020 13:06:27 -0500 Subject: [PATCH] extensions styling improvements Signed-off-by: Kenneth Marut --- .../vsx-registry/src/browser/style/index.css | 33 +++++++++++-- .../src/browser/vsx-extension-editor.tsx | 49 +++++++++++++++++-- .../src/browser/vsx-extension.tsx | 35 ++++++++++--- 3 files changed, 104 insertions(+), 13 deletions(-) diff --git a/packages/vsx-registry/src/browser/style/index.css b/packages/vsx-registry/src/browser/style/index.css index 28638106b0c88..9fe33b6106e9e 100644 --- a/packages/vsx-registry/src/browser/style/index.css +++ b/packages/vsx-registry/src/browser/style/index.css @@ -137,18 +137,45 @@ overflow: hidden; display: flex; flex-direction: column; - padding: var(--theia-ui-padding); + padding-top: 0; + position: relative; } .theia-vsx-extension-editor .header { display: flex; - padding: calc(var(--theia-ui-padding)*3) calc(var(--theia-ui-padding)*3) calc(var(--theia-ui-padding)*2); - overflow: hidden; + padding: calc(var(--theia-ui-padding) * 3) calc(var(--theia-ui-padding) * 3) calc(var(--theia-ui-padding) * 3); flex-shrink: 0; + border-bottom: 1px solid hsla(0, 0% ,50% ,.5); + position: sticky; + top: 0; + width: 100%; + background: var(--theia-editor-background); } +.theia-vsx-extension-editor .scroll-container { + position: absolute; + bottom: 0; + padding-top: 0; + max-width: 100%; +} .theia-vsx-extension-editor .body { flex: 1; + padding: calc(var(--theia-ui-padding)*2); + padding-top: 0; +} + +.theia-vsx-extension-editor .body h2:first-of-type { + padding-bottom: var(--theia-ui-padding); + border-bottom: 1px solid hsla(0, 0%, 50%, .5); + margin-top: calc(var(--theia-ui-padding) * 5); +} + +.theia-vsx-extension-editor .scroll-container .body pre { + white-space: normal; +} + +.theia-vsx-extension-editor .body img { + max-width: 100%; } .theia-vsx-extension-editor .header .icon-container { diff --git a/packages/vsx-registry/src/browser/vsx-extension-editor.tsx b/packages/vsx-registry/src/browser/vsx-extension-editor.tsx index d242e7c5a53aa..f6122461daedb 100644 --- a/packages/vsx-registry/src/browser/vsx-extension-editor.tsx +++ b/packages/vsx-registry/src/browser/vsx-extension-editor.tsx @@ -16,14 +16,20 @@ import * as React from 'react'; import { inject, injectable, postConstruct } from 'inversify'; -import { ReactWidget, Message } from '@theia/core/lib/browser'; +import { ReactWidget, Message, Widget } from '@theia/core/lib/browser'; import { VSXExtension } from './vsx-extension'; import { VSXExtensionsModel } from './vsx-extensions-model'; +import { Deferred } from '@theia/core/lib/common/promise-util'; + +const BODY_CONTENT_MAX_WIDTH = 1000; @injectable() export class VSXExtensionEditor extends ReactWidget { static ID = 'vsx-extension-editor'; + protected deferredScrollContainerRender = new Deferred(); + protected deferredHeaderElementRender = new Deferred(); + protected deferredBodyElementRender = new Deferred(); @inject(VSXExtension) protected readonly extension: VSXExtension; @@ -32,20 +38,35 @@ export class VSXExtensionEditor extends ReactWidget { protected readonly model: VSXExtensionsModel; @postConstruct() - protected init(): void { + protected async init(): Promise { this.addClass('theia-vsx-extension-editor'); this.id = VSXExtensionEditor.ID + ':' + this.extension.id; this.title.closable = true; + this.extension.deferredScrollContainerRender = this.deferredScrollContainerRender; + this.extension.deferredHeaderElementRender = this.deferredHeaderElementRender; + this.extension.deferredBodyElementRender = this.deferredBodyElementRender; this.updateTitle(); this.title.iconClass = 'fa fa-puzzle-piece'; this.node.tabIndex = -1; - this.update(); this.toDispose.push(this.model.onDidChange(() => this.update())); + await this.setContainerHeights(); + } + + async setContainerHeights(): Promise { + const headerElement = await this.deferredHeaderElementRender.promise; + const scrollContainer = await this.deferredScrollContainerRender.promise; + const headerHeight = headerElement?.clientHeight; + scrollContainer.style.height = `calc(100% - (${headerHeight}px + 1px))`; + } + + async getScrollContainer(): Promise { + return await this.deferredScrollContainerRender.promise; } protected onActivateRequest(msg: Message): void { super.onActivateRequest(msg); + this.setContainerHeights(); this.node.focus(); } @@ -54,12 +75,34 @@ export class VSXExtensionEditor extends ReactWidget { this.updateTitle(); } + protected onAfterAttach(msg: Message): void { + super.onAfterAttach(msg); + this.setContainerHeights(); + } + protected updateTitle(): void { const label = 'Extension: ' + (this.extension.displayName || this.extension.name); this.title.label = label; this.title.caption = label; } + protected async onResize(msg: Widget.ResizeMessage): Promise { + super.onResize(msg); + const bodyElement = await this.deferredBodyElementRender.promise; + const scrollContainer = await this.deferredScrollContainerRender.promise; + if (bodyElement && scrollContainer) { + scrollContainer.style.width = `${msg.width}px`; + if (msg.width > BODY_CONTENT_MAX_WIDTH) { + const sideMargin = (msg.width - BODY_CONTENT_MAX_WIDTH) / 2; + bodyElement.style.marginLeft = `${sideMargin}px`; + bodyElement.style.marginRight = `${sideMargin}px`; + } else if (msg.width <= BODY_CONTENT_MAX_WIDTH) { + bodyElement.style.marginLeft = '0px'; + bodyElement.style.marginRight = '0px'; + } + } + } + protected render(): React.ReactNode { return this.extension.renderEditor(); } diff --git a/packages/vsx-registry/src/browser/vsx-extension.tsx b/packages/vsx-registry/src/browser/vsx-extension.tsx index 8c6bf78f0b55f..0793bcfbaa38b 100644 --- a/packages/vsx-registry/src/browser/vsx-extension.tsx +++ b/packages/vsx-registry/src/browser/vsx-extension.tsx @@ -27,6 +27,7 @@ import { Endpoint } from '@theia/core/lib/browser/endpoint'; import { VSXEnvironment } from '../common/vsx-environment'; import { VSXExtensionsSearchModel } from './vsx-extensions-search-model'; import { VSXExtensionNamespaceAccess, VSXUser } from '../common/vsx-registry-types'; +import { Deferred } from '@theia/core/lib/common/promise-util'; @injectable() export class VSXExtensionData { @@ -99,6 +100,9 @@ export class VSXExtension implements VSXExtensionData, TreeElement { readonly search: VSXExtensionsSearchModel; protected readonly data: Partial = {}; + deferredScrollContainerRender: Deferred | undefined; + deferredHeaderElementRender: Deferred | undefined; + deferredBodyElementRender: Deferred | undefined; get uri(): URI { return VSXExtensionUri.toUri(this.id); @@ -351,13 +355,25 @@ export class VSXExtensionComponent extends AbstractVSXExtensionComponent { } export class VSXExtensionEditorComponent extends AbstractVSXExtensionComponent { + protected resolveDeferredOnRender( + element: HTMLDivElement | null, + deferred: Deferred | undefined): void { + if (deferred && element) { + deferred.resolve(element); + if (element.className === 'body') { + this.body = (element || undefined); + } + } + } + render(): React.ReactNode { const { - builtin, preview, id, iconUrl, publisher, displayName, description, - averageRating, downloadCount, repository, license, readme, version + builtin, preview, id, iconUrl, publisher, displayName, description, version, + averageRating, downloadCount, repository, license, readme, deferredHeaderElementRender, + deferredScrollContainerRender, deferredBodyElementRender } = this.props.extension; return -
+
this.resolveDeferredOnRender(element, deferredHeaderElementRender)}> {iconUrl ? :
} @@ -384,10 +400,15 @@ export class VSXExtensionEditorComponent extends AbstractVSXExtensionComponent { {this.renderAction()}
- {readme &&
this.body = (body || undefined)} - onClick={this.openLink} - dangerouslySetInnerHTML={{ __html: readme }} />} + {readme && +
this.resolveDeferredOnRender(element, deferredScrollContainerRender)}> +
this.resolveDeferredOnRender(element, deferredBodyElementRender)} + onClick={this.openLink} + dangerouslySetInnerHTML={{ __html: readme }} + /> +
+ } ; }