Skip to content

Commit

Permalink
refactor: tweak style for overlay
Browse files Browse the repository at this point in the history
  • Loading branch information
malcolm-kee committed Sep 21, 2022
1 parent 418e932 commit 0313243
Show file tree
Hide file tree
Showing 8 changed files with 363 additions and 45 deletions.
84 changes: 39 additions & 45 deletions client-src/overlay.js
Expand Up @@ -3,6 +3,15 @@

import ansiHTML from "ansi-html-community";
import { encode } from "html-entities";
import {
containerStyle,
dismissButtonStyle,
headerStyle,
iframeStyle,
msgStyles,
msgTextStyle,
msgTypeStyle,
} from "./overlay/styles.js";

const colors = {
reset: ["transparent", "transparent"],
Expand All @@ -28,6 +37,17 @@ let overlayTrustedTypesPolicy;

ansiHTML.setColors(colors);

/**
*
* @param {HTMLElement} element
* @param {CSSStyleDeclaration} style
*/
function applyStyle(element, style) {
Object.keys(style).forEach((prop) => {
element.style[prop] = style[prop];
});
}

/**
* @param {string | null} trustedTypesPolicyName
*/
Expand All @@ -45,64 +65,35 @@ function createContainer(trustedTypesPolicyName) {
iframeContainerElement = document.createElement("iframe");
iframeContainerElement.id = "webpack-dev-server-client-overlay";
iframeContainerElement.src = "about:blank";
iframeContainerElement.style.position = "fixed";
iframeContainerElement.style.left = 0;
iframeContainerElement.style.top = 0;
iframeContainerElement.style.right = 0;
iframeContainerElement.style.bottom = 0;
iframeContainerElement.style.width = "100vw";
iframeContainerElement.style.height = "100vh";
iframeContainerElement.style.border = "none";
iframeContainerElement.style.zIndex = 9999999999;
applyStyle(iframeContainerElement, iframeStyle);
iframeContainerElement.onload = () => {
containerElement =
/** @type {Document} */
(
/** @type {HTMLIFrameElement} */
(iframeContainerElement).contentDocument
).createElement("div");

containerElement.id = "webpack-dev-server-client-overlay-div";
containerElement.style.position = "fixed";
containerElement.style.boxSizing = "border-box";
containerElement.style.left = 0;
containerElement.style.top = 0;
containerElement.style.right = 0;
containerElement.style.bottom = 0;
containerElement.style.width = "100vw";
containerElement.style.height = "100vh";
containerElement.style.backgroundColor = "rgba(0, 0, 0, 0.85)";
containerElement.style.color = "#E8E8E8";
containerElement.style.fontFamily = "Menlo, Consolas, monospace";
containerElement.style.fontSize = "large";
containerElement.style.padding = "2rem";
containerElement.style.lineHeight = "1.2";
containerElement.style.whiteSpace = "pre-wrap";
containerElement.style.overflow = "auto";

const headerElement = document.createElement("span");
applyStyle(containerElement, containerStyle);

const headerElement = document.createElement("div");

headerElement.innerText = "Compiled with problems:";
applyStyle(headerElement, headerStyle);

const closeButtonElement = document.createElement("button");

closeButtonElement.innerText = "X";
closeButtonElement.style.background = "transparent";
closeButtonElement.style.border = "none";
closeButtonElement.style.fontSize = "20px";
closeButtonElement.style.fontWeight = "bold";
closeButtonElement.style.color = "white";
closeButtonElement.style.cursor = "pointer";
closeButtonElement.style.cssFloat = "right";
// @ts-ignore
closeButtonElement.style.styleFloat = "right";
applyStyle(closeButtonElement, dismissButtonStyle);

closeButtonElement.innerText = "×";
closeButtonElement.ariaLabel = "Dismiss";
closeButtonElement.addEventListener("click", () => {
hide();
});

containerElement.appendChild(headerElement);
containerElement.appendChild(closeButtonElement);
containerElement.appendChild(document.createElement("br"));
containerElement.appendChild(document.createElement("br"));

/** @type {Document} */
(
Expand Down Expand Up @@ -200,26 +191,29 @@ function show(type, messages, trustedTypesPolicyName) {
ensureOverlayExists(() => {
messages.forEach((message) => {
const entryElement = document.createElement("div");
const typeElement = document.createElement("span");
const msgStyle = type === "warning" ? msgStyles.warning : msgStyles.error;
applyStyle(entryElement, {
...msgStyle,
padding: "1rem 1rem 1.5rem 1rem",
});

const typeElement = document.createElement("div");
const { header, body } = formatProblem(type, message);

typeElement.innerText = header;
typeElement.style.color = `#${colors.red}`;
applyStyle(typeElement, msgTypeStyle);

// Make it look similar to our terminal.
const text = ansiHTML(encode(body));
const messageTextNode = document.createElement("div");
applyStyle(messageTextNode, msgTextStyle);

messageTextNode.innerHTML = overlayTrustedTypesPolicy
? overlayTrustedTypesPolicy.createHTML(text)
: text;

entryElement.appendChild(typeElement);
entryElement.appendChild(document.createElement("br"));
entryElement.appendChild(document.createElement("br"));
entryElement.appendChild(messageTextNode);
entryElement.appendChild(document.createElement("br"));
entryElement.appendChild(document.createElement("br"));

/** @type {HTMLDivElement} */
(containerElement).appendChild(entryElement);
Expand Down
89 changes: 89 additions & 0 deletions client-src/overlay/styles.js
@@ -0,0 +1,89 @@
// styles are inspired by `react-error-overlay`

const msgStyles = {
error: {
backgroundColor: "rgba(206, 17, 38, 0.1)",
color: "#fccfcf",
},
warning: {
backgroundColor: "rgba(251, 245, 180, 0.1)",
color: "#fbf5b4",
},
};

const iframeStyle = {
position: "fixed",
top: 0,
left: 0,
right: 0,
bottom: 0,
width: "100vw",
height: "100vh",
border: "none",
"z-index": 9999999999,
};

const containerStyle = {
position: "fixed",
boxSizing: "border-box",
left: 0,
top: 0,
right: 0,
bottom: 0,
width: "100vw",
height: "100vh",
fontSize: "large",
padding: "2rem 2rem 4rem 2rem",
lineHeight: "1.2",
whiteSpace: "pre-wrap",
overflow: "auto",
backgroundColor: "rgba(0, 0, 0, 0.9)",
color: "white",
};

const headerStyle = {
color: "#e83b46",
fontSize: "2em",
whiteSpace: "pre-wrap",
fontFamily: "sans-serif",
margin: "0 2rem 2rem 0",
flex: "0 0 auto",
maxHeight: "50%",
overflow: "auto",
};

const dismissButtonStyle = {
color: "#ffffff",
lineHeight: "1rem",
fontSize: "1.5rem",
padding: "1rem",
cursor: "pointer",
position: "absolute",
right: 0,
top: 0,
backgroundColor: "transparent",
border: "none",
};

const msgTypeStyle = {
color: "#e83b46",
fontSize: "1.2em",
marginBottom: "1rem",
fontFamily: "sans-serif",
};

const msgTextStyle = {
lineHeight: "1.5",
fontSize: "1rem",
fontFamily: "Menlo, Consolas, monospace",
};

export {
msgStyles,
iframeStyle,
containerStyle,
headerStyle,
dismissButtonStyle,
msgTypeStyle,
msgTextStyle,
};
20 changes: 20 additions & 0 deletions examples/client/overlay-complex/README.md
@@ -0,0 +1,20 @@
# client.overlay option

**webpack.config.js**

```js
module.exports = {
// ...
devServer: {
client: {
overlay: true,
},
},
};
```

Usage via CLI:

```shell
npx webpack serve --open --client-overlay
```
3 changes: 3 additions & 0 deletions examples/client/overlay-complex/src/app.ts
@@ -0,0 +1,3 @@
let string = "hello";

string = 5;
7 changes: 7 additions & 0 deletions examples/client/overlay-complex/tsconfig.json
@@ -0,0 +1,7 @@
{
"compilerOptions": {
"moduleResolution": "node",
"sourceMap": true
},
"include": ["src"]
}
27 changes: 27 additions & 0 deletions examples/client/overlay-complex/webpack.config.js
@@ -0,0 +1,27 @@
"use strict";

// our setup function adds behind-the-scenes bits to the config that all of our
// examples need
const { setup } = require("../../util");

module.exports = setup({
context: __dirname,
entry: "./src/app.ts",
devtool: "inline-source-map",
devServer: {
client: {
overlay: true,
},
},
resolve: {
extensions: [".ts", ".tsx", ".js"],
},
module: {
rules: [
{
test: /\.tsx?$/,
loader: "ts-loader",
},
],
},
});

0 comments on commit 0313243

Please sign in to comment.