Skip to content

Commit

Permalink
tweak website
Browse files Browse the repository at this point in the history
  • Loading branch information
Brian Kim committed Feb 14, 2024
1 parent b3da1ef commit db4ed71
Show file tree
Hide file tree
Showing 10 changed files with 925 additions and 352 deletions.
981 changes: 797 additions & 184 deletions website/package-lock.json

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion website/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"@emotion/server": "^11.10.0",
"@esbuild-plugins/node-globals-polyfill": "^0.2.3",
"@esbuild-plugins/node-modules-polyfill": "^0.2.2",
"@lezer/javascript": "^1.4.13",
"@remix-run/web-fetch": "^4.3.2",
"@tanstack/virtual-core": "^3.0.0-alpha.1",
"@types/babel__core": "^7.20.0",
Expand All @@ -29,7 +30,7 @@
"@types/postcss-preset-env": "^7.7.0",
"@types/prismjs": "^1.26.0",
"chokidar": "^3.5.3",
"esbuild": "^0.17.10",
"esbuild": "^0.20.0",
"front-matter": "^4.0.2",
"gh-pages": "^5.0.0",
"http-server": "^14.1.1",
Expand Down
6 changes: 3 additions & 3 deletions website/src/clients/code-blocks.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import {jsx} from "@b9g/crank/standalone";
import {renderer} from "@b9g/crank/dom";

window.Prism = window.Prism || {};
Prism.manual = true;
import Prism from "prismjs";
// TODO: lazily import these?
import "prismjs/components/prism-javascript";
Expand All @@ -9,14 +11,12 @@ import "prismjs/components/prism-typescript";
import "prismjs/components/prism-tsx";
import "prismjs/components/prism-diff";
import "prismjs/components/prism-bash";

import {ContentAreaElement} from "@b9g/revise/contentarea.js";
import {InlineCodeBlock} from "../components/inline-code-block.js";
import {extractData} from "../components/serialize-javascript.js";
import {GearInteractive} from "../components/gear-interactive.js";

// @ts-ignore
Prism.manual = true;

if (!window.customElements.get("content-area")) {
window.customElements.define("content-area", ContentAreaElement);
}
Expand Down
18 changes: 9 additions & 9 deletions website/src/clients/playground.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ if (!window.customElements.get("content-area")) {
window.customElements.define("content-area", ContentAreaElement);
}

function CodeEditorNavbar({children}) {
function CodeEditorNavbar({children}: any) {
return jsx`
<div class=${css`
flex: none;
Expand All @@ -34,26 +34,26 @@ function CodeEditorNavbar({children}) {
`;
}

const examples = extractData(document.getElementById("examples"));
const examples = extractData(
document.getElementById("examples") as HTMLScriptElement,
);

function* Playground(this: Context, {}) {
function* Playground(this: Context) {
let code = localStorage.getItem("playground-value") || "";
if (!code.trim()) {
code = examples[0].code;
}

this.addEventListener("contentchange", (ev: any) => {
code = ev.target.value;

localStorage.setItem("playground-value", code);
this.refresh();
});

let exampleName: "" | "timer" | "tetris" = "";
let exampleName = "";
const onexamplechange = (ev: Event) => {
exampleName = (ev.target as HTMLSelectElement).value;
const {code: code1} = examples.find(
(example) => example.name === exampleName,
(example: any) => example.name === exampleName,
);
code = code1;
this.refresh();
Expand Down Expand Up @@ -100,9 +100,9 @@ function* Playground(this: Context, {}) {
value=${exampleName}
onchange=${onexamplechange}
>
<option value="" key=${name}>Load an example...</option>
<option value="">Load an example...</option>
${examples.map(
({name, label}) => jsx`
({name, label}: any) => jsx`
<option value=${name} key=${name}>${label}</option>
`,
)}
Expand Down
176 changes: 60 additions & 116 deletions website/src/components/code-editor.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {jsx} from "@b9g/crank/standalone";
import {Copy, jsx} from "@b9g/crank/standalone";
import type {Context, Element as CrankElement} from "@b9g/crank";
import {css} from "@emotion/css";
import {Edit} from "@b9g/revise/edit.js";
Expand All @@ -8,54 +8,60 @@ import {EditHistory} from "@b9g/revise/history.js";
import type {ContentAreaElement} from "@b9g/revise/contentarea.js";

import type {Token} from "prismjs";

//import {parser} from "@lezer/javascript";
import {ContentArea} from "./contentarea.js";
import {tokenize} from "../utils/prism.js";
import {useVirtualizer} from "../utils/virtualizer.js";
import type {Virtualizer} from "../utils/virtualizer.js";
import {debounce} from "../utils/fns.js";

function Gutter(
this: Context<typeof Gutter>,
{virtualizer}: {virtualizer: Virtualizer<any, any>},
) {
const items = virtualizer.getVirtualItems();
const totalSize = virtualizer.getTotalSize();
return jsx`
<div
class="blur-background ${css`
display: none;
@media (min-width: 800px) {
display: block;
}
function* Gutter(this: Context<typeof Gutter>, {length}: {length: number}) {
let initial = true;
let newLength: number;
const lines = Array.from({length}, (_, i) => i + 1);
for ({length: newLength} of this) {
if (length === newLength) {
if (!initial) {
yield jsx`<${Copy} />`;
continue;
}
} else {
if (length < newLength) {
lines.push(
...Array.from({length: newLength - length}, (_, i) => i + length + 1),
);
} else {
lines.splice(newLength);
}
}

flex: none;
margin: 0;
padding: 1em 0.5em;
color: var(--text-color);
font-size: 16px;
font-family: monospace;
line-height: 1.4;
text-align: right;
border-right: 1px solid var(--text-color);
position: sticky;
left: 0;
`}"
style="height: max(calc(100vh - 50px), ${totalSize + 50}px);"
>
yield jsx`
<div
class=${css`
position: relative;
top: ${items[0]?.start}px;
`}
static=${length === newLength}
class="blur-background ${css`
display: none;
@media (min-width: 800px) {
display: flex;
}
flex-direction: column;
flex: none;
margin: 0;
padding: 1em 0.5em;
color: var(--text-color);
font-size: 16px;
font-family: monospace;
line-height: 1.4;
text-align: right;
border-right: 1px solid var(--text-color);
position: sticky;
left: 0;
`}"
>
${items.map(
(item) => jsx`
<div style="height: ${item.size}px">${item.index + 1}</div>
`,
)}
<!-- TODO: don't hardcode the height -->
${lines.map((line) => jsx`<div style="height: 23px">${line}</div>`)}
</div>
</div>
`;
`;
initial = false;
length = newLength;
}
}

const IS_CLIENT = typeof document !== "undefined";
Expand Down Expand Up @@ -133,7 +139,6 @@ export function* CodeEditor(
},
) {
const keyer = new Keyer();
let editHistory = new EditHistory();
let selectionRange: SelectionRange | undefined;
let renderSource: string | undefined;
let area!: ContentAreaElement;
Expand Down Expand Up @@ -163,30 +168,12 @@ export function* CodeEditor(

value = ev.target.value;
renderSource = "refresh";
currentEdit = ev.detail.edit;
this.refresh();
});

const virtualizer = useVirtualizer(this, {
count: 0,
getScrollElement: () => {
return getScroller(area);
},
// Debouncing because calling measureElement causes this function to fire
// multiple times.
onChange: debounce(() => {
//value = area.value;
//renderSource = "virtualizer";
this.refresh();
}, 0),
estimateSize: () => {
return 19;
},
// TODO: read this from the DOM and un-hardcode
scrollPaddingStart: 14,
scrollPaddingEnd: 14,
overscan: 100,
});

let editHistory = new EditHistory();
let currentEdit: Edit | undefined;

Check failure on line 176 in website/src/components/code-editor.ts

View workflow job for this annotation

GitHub Actions / build

'currentEdit' is assigned a value but never used. Allowed unused vars must match /^_/u
{
// history stuff
const undo = () => {
Expand All @@ -196,6 +183,7 @@ export function* CodeEditor(
selectionRange = selectionRangeFromEdit(edit);
keyer.transform(edit);
renderSource = "history";
currentEdit = edit;
this.refresh();
return true;
}
Expand All @@ -210,6 +198,7 @@ export function* CodeEditor(
selectionRange = selectionRangeFromEdit(edit);
keyer.transform(edit);
renderSource = "history";
currentEdit = edit;
this.refresh();
return true;
}
Expand Down Expand Up @@ -307,6 +296,8 @@ export function* CodeEditor(
this.refresh();
} else if (ev.key === "Tab") {
// TODO:
} else if (ev.key === "Escape") {
// TODO:
}
});
}
Expand All @@ -319,43 +310,16 @@ export function* CodeEditor(
renderSource = undefined;
});

this.flush((el) => {
const pre = el.querySelector("pre")!;
for (let i = 0; i < pre.children.length; i++) {
const child = pre.children[i];
virtualizer.measureElement(child);
}
});

if (renderSource == null) {
// Very perplexing.
value = value1;
}

// make sure the value always ends with a newline
value = value.match(/(?:\r|\n|\r\n)$/) ? value : value + "\n";

const lineStarts: Array<number> = [];
{
// remove last empty line
const lines = value.split(/\n/).slice(0, -1);
for (let i = 0, c = 0; i < lines.length; i++) {
lineStarts.push(c);
c += lines[i].length + 1;
}

virtualizer.setOptions({
...virtualizer.options,
count: lines.length,
});
}

const lines = tokenize(value, language || "javascript");
const lineTokens = tokenize(value, language || "javascript");
let index = 0;
//const items = virtualizer.getVirtualItems();
//const start = items[0]?.index || 0;
//const end = items[items.length - 1]?.index || 0;
yield jsx`
const result = jsx`
<div
class=${css`
position: relative;
Expand All @@ -364,17 +328,7 @@ export function* CodeEditor(
display: flex;
`}
>
${
showGutter &&
jsx`
<${Gutter}
length=${lines.length}
lineStarts=${lineStarts}
virtualizer=${virtualizer}
keyer=${keyer}
/>
`
}
${showGutter && jsx`<${Gutter} length=${lineTokens.length} />`}
<${ContentArea}
ref=${(el: ContentAreaElement) => (area = el)}
value=${value}
Expand Down Expand Up @@ -404,7 +358,7 @@ export function* CodeEditor(
`}
"
>
${lines.map((line, l) => {
${lineTokens.map((line, l) => {
// TODO: only highlight visible lines
// TODO: line should probably be a custom Prism token with the
// length already calculated.
Expand All @@ -427,20 +381,10 @@ export function* CodeEditor(
</${ContentArea}>
</div>
`;
yield result;
}
}

function getScroller(el: Element | null): Element | null {
for (; el != null; el = el.parentElement) {
const overflowY = window.getComputedStyle(el).overflowY;
if (overflowY === "auto" || overflowY === "scroll") {
return el;
}
}

return document.scrollingElement;
}

function getPreviousLine(text: string, index: number) {
index = Math.max(0, index);
for (let i = index - 1; i >= 0; i--) {
Expand Down
Loading

0 comments on commit db4ed71

Please sign in to comment.