Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add redesign feature flag #392

Merged
merged 8 commits into from
Feb 3, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/Elastic.Markdown/.postcssrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"plugins": {
"@tailwindcss/postcss": {},
"postcss-import": {},
}
}
180 changes: 180 additions & 0 deletions src/Elastic.Markdown/Assets/hljs-merge-html-plugin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
export const mergeHTMLPlugin = (function () {
'use strict';

var originalStream;

/**
* @param {string} value
* @returns {string}
*/
function escapeHTML(value) {
return value
.replace(/&/g, '&')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#x27;');
}

/* plugin itself */

/** @type {HLJSPlugin} */
const mergeHTMLPlugin = {
// preserve the original HTML token stream
"before:highlightElement": ({ el }) => {
originalStream = nodeStream(el);
},
// merge it afterwards with the highlighted token stream
"after:highlightElement": ({ el, result, text }) => {
if (!originalStream.length) return;

const resultNode = document.createElement('div');
resultNode.innerHTML = result.value;
result.value = mergeStreams(originalStream, nodeStream(resultNode), text);
el.innerHTML = result.value;
}
};

/* Stream merging support functions */

/**
* @typedef Event
* @property {'start'|'stop'} event
* @property {number} offset
* @property {Node} node
*/

/**
* @param {Node} node
*/
function tag(node) {
return node.nodeName.toLowerCase();
}

/**
* @param {Node} node
*/
function nodeStream(node) {
/** @type Event[] */
const result = [];
(function _nodeStream(node, offset) {
for (let child = node.firstChild; child; child = child.nextSibling) {
if (child.nodeType === 3) {
offset += child.nodeValue.length;
} else if (child.nodeType === 1) {
result.push({
event: 'start',
offset: offset,
node: child
});
offset = _nodeStream(child, offset);
// Prevent void elements from having an end tag that would actually
// double them in the output. There are more void elements in HTML
// but we list only those realistically expected in code display.
if (!tag(child).match(/br|hr|img|input/)) {
result.push({
event: 'stop',
offset: offset,
node: child
});
}
}
}
return offset;
})(node, 0);
return result;
}

/**
* @param {any} original - the original stream
* @param {any} highlighted - stream of the highlighted source
* @param {string} value - the original source itself
*/
function mergeStreams(original, highlighted, value) {
let processed = 0;
let result = '';
const nodeStack = [];

function selectStream() {
if (!original.length || !highlighted.length) {
return original.length ? original : highlighted;
}
if (original[0].offset !== highlighted[0].offset) {
return (original[0].offset < highlighted[0].offset) ? original : highlighted;
}

/*
To avoid starting the stream just before it should stop the order is
ensured that original always starts first and closes last:

if (event1 == 'start' && event2 == 'start')
return original;
if (event1 == 'start' && event2 == 'stop')
return highlighted;
if (event1 == 'stop' && event2 == 'start')
return original;
if (event1 == 'stop' && event2 == 'stop')
return highlighted;

... which is collapsed to:
*/
return highlighted[0].event === 'start' ? original : highlighted;
}

/**
* @param {Node} node
*/
function open(node) {
/** @param {Attr} attr */
function attributeString(attr) {
return ' ' + attr.nodeName + '="' + escapeHTML(attr.value) + '"';
}
// @ts-ignore
result += '<' + tag(node) + [].map.call(node.attributes, attributeString).join('') + '>';
}

/**
* @param {Node} node
*/
function close(node) {
result += '</' + tag(node) + '>';
}

/**
* @param {Event} event
*/
function render(event) {
(event.event === 'start' ? open : close)(event.node);
}

while (original.length || highlighted.length) {
let stream = selectStream();
result += escapeHTML(value.substring(processed, stream[0].offset));
processed = stream[0].offset;
if (stream === original) {
/*
On any opening or closing tag of the original markup we first close
the entire highlighted node stack, then render the original tag along
with all the following original tags at the same offset and then
reopen all the tags on the highlighted stack.
*/
nodeStack.reverse().forEach(close);
do {
render(stream.splice(0, 1)[0]);
stream = selectStream();
} while (stream === original && stream.length && stream[0].offset === processed);
nodeStack.reverse().forEach(open);
} else {
if (stream[0].event === 'start') {
nodeStack.push(stream[0].node);
} else {
nodeStack.pop();
}
render(stream.splice(0, 1)[0]);
}
}
return result + escapeHTML(value.substr(processed));
}

return mergeHTMLPlugin;
}());
18 changes: 18 additions & 0 deletions src/Elastic.Markdown/Assets/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import hljs from "highlight.js";
import {mergeHTMLPlugin} from "./hljs-merge-html-plugin";

hljs.registerLanguage('apiheader', function() {
return {
case_insensitive: true, // language is case-insensitive
keywords: 'GET POST PUT DELETE HEAD OPTIONS PATCH',
contains: [
hljs.HASH_COMMENT_MODE,
{
className: "subst", // (pathname: path1/path2/dothis) color #ab5656
begin: /(?<=(?:\/|GET |POST |PUT |DELETE |HEAD |OPTIONS |PATH))[^?\n\r\/]+/,
}
], }
})

hljs.addPlugin(mergeHTMLPlugin);
hljs.highlightAll();
29 changes: 29 additions & 0 deletions src/Elastic.Markdown/Assets/markdown/typography.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#elastic-docs-v3 {
h1 {
@apply text-4xl text-ink font-semibold mb-6;
line-height: 1.2em;
letter-spacing: -0.04em;
}

h2 {
@apply text-2xl text-ink font-bold mb-6;
line-height: 1.2em;
letter-spacing: -0.02em;
}

h3 {
@apply text-xl text-ink font-bold mb-6;
line-height: 1.2em;
letter-spacing: -0.02em;
}

p {
@apply text-base text-body mb-6;
line-height: 1.5em;
letter-spacing: 0;
}

a {
@apply text-blue-elastic hover:underline underline-offset-4;
}
}
16 changes: 8 additions & 8 deletions src/Elastic.Markdown/Assets/styles.css
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
@import "legacy/pygments.css";
@import "legacy/shibuya.css";
@import "legacy/mystnb.css";
@import "legacy/copybutton.css";
@import "legacy/togglebutton.css";
@import "legacy/sphinx-design.min.css";
@import "legacy/custom.css";
@import "legacy/atom-one-light.css";
@import "tailwindcss";
@import "highlight.js/styles/atom-one-dark.css";
@import "./theme.css";
@import "./markdown/typography.css";

main.markdown-content {
max-width: 80ch;
}
44 changes: 44 additions & 0 deletions src/Elastic.Markdown/Assets/theme.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
@theme {
--color-*: initial;

--color-white: #FFFFFF;
--color-black: #000000;

--color-body: #515151;

--color-ink: #343741;
--color-ink-light: #535966;
--color-ink-dark: #1C1E23;

--color-gray: #E6EBF2;
--color-gray-light: #F5F7FA;
--color-gray-dark: #D4DAE5;

--color-blue-elastic: #0077CC;
--color-blue-sky: #36B9FF;
--color-blue-midnight: #20377D;

--color-red-light: #FB6363;
--color-red-dark: #D93333;

--color-green-light: #3CD278;
--color-green-dark: #148742;

--color-teal: #00BFB3;
--color-teal-light: #48EFCF;
--color-teal-dark: #00857F;

--color-poppy: #FA744E;
--color-poppy-light: #FF957D;
--color-poppy-dark: #E2543D;

--color-pink: #F04E98;
--color-pink-light: #F990C6;
--color-pink-dark: #DD0A73;

--color-yellow: #FEC514;
--color-yellow-light: #FFD836;
--color-yellow-dark: #F9B110;

--spacing: 4px;
}
21 changes: 14 additions & 7 deletions src/Elastic.Markdown/Slices/Layout/_Head.cshtml
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,24 @@
<link rel="index" title="Index" href="@Model.Link("genindex.html")"/>
<link rel="search" title="Search" href="@Model.Link("search.html")"/>
<link rel="next" title="Elastic content" href="elastic/index.html"/>
<link rel="stylesheet" type="text/css" href="@Model.Static("styles.css")"/>
<link media="print" rel="stylesheet" type="text/css" href="@Model.Static("print.css")"/>
<link rel="stylesheet" type="text/css" href="@Model.Static("pygments.css")"/>
<link rel="stylesheet" type="text/css" href="@Model.Static("shibuya.css")"/>
<link rel="stylesheet" type="text/css" href="@Model.Static("mystnb.css")"/>
<link rel="stylesheet" type="text/css" href="@Model.Static("copybutton.css")"/>
<link rel="stylesheet" type="text/css" href="@Model.Static("togglebutton.css")"/>
<link rel="stylesheet" type="text/css" href="@Model.Static("sphinx-design.min.css")"/>
<link media="print" rel="stylesheet" type="text/css" href="@Model.Static("/_static/print.css")"/>
<link rel="stylesheet" type="text/css" href="@Model.Static("custom.css")"/>
<link rel="stylesheet" type="text/css" href="@Model.Static("atom-one-light.css")"/>
Comment on lines +10 to +18
Copy link
Member Author

@reakaleek reakaleek Feb 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reverting the old css here, so that the parcel setup only has the new styles.

<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
<style>
:root {
--sy-f-text: "Inter", var(--sy-f-sys), var(--sy-f-cjk), sans-serif;
--sy-f-heading: "Inter", var(--sy-f-sys), var(--sy-f-cjk), sans-serif;
}
</style>
:root {
--sy-f-text: "Inter", var(--sy-f-sys), var(--sy-f-cjk), sans-serif;
--sy-f-heading: "Inter", var(--sy-f-sys), var(--sy-f-cjk), sans-serif;
}
</style>
<meta property="og:type" content="website"/>
<meta property="og:title" content="Elastic Docs v3"/>
<meta name="twitter:card" content="summary"/>
Expand Down
30 changes: 29 additions & 1 deletion src/Elastic.Markdown/Slices/_Layout.cshtml
Original file line number Diff line number Diff line change
@@ -1,4 +1,31 @@
@inherits RazorLayoutSlice<LayoutViewModel>
@if (Model.IsRedesign)
{
<!DOCTYPE html>
<html lang="en">
<head>
<title>@Model.Title</title>
<link rel="stylesheet" type="text/css" href="@Model.Static("styles.css")"/>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="robots" content="@(Model.AllowIndexing ? "index, follow" : "noindex, nofollow")">
</head>
<body class="text-ink flex flex-col min-h-screen">
<div id="elastic-nav"></div>
<script src='https://www.elastic.co/elastic-nav.js'></script>

<main class="markdown-content max-w-7xl mx-auto p-6 flex-1">
@await RenderBodyAsync()
</main>

<div id="elastic-footer"></div>
<script src='https://www.elastic.co/elastic-footer.js'></script>
<script src="@Model.Static("main.js")"></script>
</body>
</html>
}
else
{
<!DOCTYPE html>
<html lang="en" data-accent-color="blue" data-content_root="./">
@(await RenderPartialAsync(_Head.Create(Model)))
Expand Down Expand Up @@ -98,4 +125,5 @@
@await RenderSectionAsync("scripts")

</body>
</html>
</html>
}
2 changes: 2 additions & 0 deletions src/Elastic.Markdown/Slices/_ViewModels.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ public class LayoutViewModel
public required string? GithubEditUrl { get; set; }
public required bool AllowIndexing { get; init; }

public bool IsRedesign => Environment.GetEnvironmentVariable("REDESIGN") == "true";

private MarkdownFile[]? _parents;
public MarkdownFile[] Parents
{
Expand Down
Loading