Skip to content

Commit

Permalink
docs: add copy button to code blocks, add setup page (#990)
Browse files Browse the repository at this point in the history
  • Loading branch information
ssalbdivad committed May 31, 2024
1 parent c412501 commit 1195c09
Show file tree
Hide file tree
Showing 29 changed files with 288 additions and 129 deletions.
39 changes: 17 additions & 22 deletions ark/dark/README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<div align="center">
<img src="./icon.png" height="64px" />
<img src="/ark/dark/icon.png" height="64px" />
<h1>ArkDark</h1>
</div>
<div align="center">
Expand All @@ -14,41 +14,36 @@ We're building a 1:1 validator for TypeScript! Check out our core project [on Gi

This extension provides syntax highlighting for strings that are part of an ArkType definition:

![syntax highlighting](./highlighting.png)
![syntax highlighting](/ark/dark/highlighting.png)

## ArkDark Theme

It also includes an editor theme based on ArkType and optimized for type syntax:

![theme](./theme.png)
![theme](/ark/dark/theme.png)

## Extending This Theme
## Contributing

- **pnpm build** to generate the arkdark.json theme
- **F5** or **Run > Debugger**, will launch the extension in another window, allowing you to see the changes on any repo you open up
**Run > Debugger** (`F5` by default) will launch the extension in another window, allowing you to see the effects of your changes on whatever code you open in it.

Looking to edit the theme? **(Changes are immediately reflected)**
### Update the ArkDark theme palette

- **themes** > **arkdark.json**
See [color-theme.json](/ark/dark/color-theme.json)

Looking to change the textmate scopes? **(Must restart the debugger to view changes)**
> [!NOTE]
> Changes will be immediately reflected in the extension host window
- arktype.tmLanguage.json
### Update syntax highlighting rules

Current textmate scopes can be viewed:
See [injected.tmLanguage.json](/ark/dark/injected.tmLanguage.json)

- Open: Command Palette **(Ctrl + Shift + P)**
- Search: **Developer: Inspect Editor Tokens and Scopes**
To determine which scopes need to be changed, you can view scopes applied to any file in VSCode by opening the Command Palette (Ctrl+Shift+P by default) and searching "Developer: Inspect Editor Tokens and Scopes".

## Notes
Changes to `injected.tmLanguage.json` should be mirrored to [tsWithArkType.tmLanguage.json](./tsWithArkType.tmLanguage.json).

Base color-theme.json copied from VSCode's "Default Dark Modern" (https://github.com/microsoft/vscode/blob/main/extensions/theme-defaults/themes/dark_modern.json).
> [!IMPORTANT]
> You must reload the extension host window to see scope changes reflected
These are the original colors of defaults that have been overriden:
## Attributions

```json
{
"editor.foreground": "#CCCCCC",
"errorForeground": "#F85149"
}
```
Base color-theme.json extended from VSCode's "Default Dark Modern" (https://github.com/microsoft/vscode/blob/main/extensions/theme-defaults/themes/dark_modern.json).
2 changes: 1 addition & 1 deletion ark/dark/injected.tmLanguage.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json",
"name": "InjectedArkTypeScript",
"scopeName": "source.arktype.injection.ts",
"injectionSelector": "L:source.ts - comment",
"injectionSelector": "L:source.ts, L:source.tsx, L:source.js, L:source.jsx, L:source.mdx, L:meta.embedded.block.typescript, L:meta.embedded.block.typescriptreact, L:meta.embedded.block.javascript - comment",
"patterns": [
{
"include": "#arkDefinition"
Expand Down
8 changes: 5 additions & 3 deletions ark/dark/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "arkdark",
"displayName": "ArkDark",
"description": "ArkType syntax highlighting and theme⛵",
"version": "5.1.7",
"version": "5.2.1",
"publisher": "arktypeio",
"type": "module",
"scripts": {
Expand Down Expand Up @@ -41,9 +41,11 @@
{
"injectTo": [
"source.ts",
"source.ts.tsx",
"source.tsx",
"source.js",
"source.js.jsx"
"source.jsx",
"source.mdx",
"text.html.markdown"
],
"scopeName": "source.arktype.injection.ts",
"path": "injected.tmLanguage.json"
Expand Down
14 changes: 8 additions & 6 deletions ark/docs/astro.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ export default defineConfig({
{
tag: "script",
content: `localStorage.setItem("starlight-theme", "dark")`
},
{
tag: "script",
attrs: {
src: "/src/components/addCopyButtonListeners.js"
}
}
],
social: {
Expand All @@ -37,15 +43,11 @@ export default defineConfig({
sidebar: [
{
label: "Intro",
items: [{ label: "Install", link: "/intro/install/" }]
autogenerate: { directory: "intro" }
},
{
label: "Reference",
items: [
{ label: "Your first type", link: "/reference/your-first-type/" },
{ label: "Scopes", link: "/reference/scopes/" },
{ label: "Cheat sheet", link: "/reference/cheat-sheet/" }
]
autogenerate: { directory: "reference" }
}
],
customCss: ["@shikijs/twoslash/style-rich.css", "./src/styles.css"],
Expand Down
Binary file removed ark/docs/src/assets/CascadiaCodeLig.ttf
Binary file not shown.
4 changes: 4 additions & 0 deletions ark/docs/src/assets/check.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions ark/docs/src/assets/copy.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
---
import { arkHighlight } from "./highlight.ts"
import { arkHighlight, type HighlightArgs, type BuiltinLang } from "./highlight.ts"
// ideally we could just import { Code } from "astro:components" instead of
// using this custom component, but as of now, the `Code` component imported from
// `astro:components` does not apply our shikiConfig.
// If it does in the future, this component can be deleted.
interface Props {
interface Props extends HighlightArgs {
code: string
lang?: BuiltinLang
}
const { code } = Astro.props
const html = await arkHighlight(code)
const html = await arkHighlight(Astro.props)
---

<Fragment set:html={html} />
<Fragment set:html={html} />
45 changes: 45 additions & 0 deletions ark/docs/src/components/addCopyButtonListeners.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
const hoverSelector = ".twoslash-popup-code"
const errorSelector = ".twoslash-error-line"
const completionSelector = ".twoslash-completion-cursor"
const metaSelector = `${hoverSelector}, ${errorSelector}, ${completionSelector}`

const distillTwoslashCode = container => {
const walker = document.createTreeWalker(container, NodeFilter.SHOW_TEXT)

let src = ""
while (walker.nextNode()) {
/** @type { Element } */
const parentNode = walker.currentNode.parentNode
if (parentNode.closest(errorSelector)) {
// if a twoslash error was rendered in this position, we need an additional newline
src += "\n"
}
if (!parentNode?.closest(metaSelector)) {
// if the node is not a meta node (hover, error or completion) add its textContent
src += walker.currentNode.textContent ?? ""
}
}

return src.trim()
}

globalThis.addCopyButtonListeners = () => {
document.querySelectorAll(".code-container").forEach(codeContainer => {
const copyButton = codeContainer.querySelector(".copy-button")
const icon = codeContainer.querySelector(".copy-icon")

copyButton.addEventListener("click", async () => {
const textToCopy = distillTwoslashCode(codeContainer)
await navigator.clipboard.writeText(textToCopy)

icon.setAttribute("src", "/src/assets/check.svg")
copyButton.setAttribute("disabled", "1")
copyButton.setAttribute("style", "opacity: .6;")
setTimeout(() => {
icon.setAttribute("src", "/src/assets/copy.svg")
copyButton.removeAttribute("disabled")
copyButton.removeAttribute("style")
}, 2000)
})
})
}
19 changes: 13 additions & 6 deletions ark/docs/src/components/highlight.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,25 @@
import arkdarkColors from "arkdark/color-theme.json"
import arktypeTextmate from "arkdark/tsWithArkType.tmLanguage.json"
import { getHighlighter } from "shiki"
import { twoslash } from "./shiki.config.js"
import { addCopyButton, twoslash } from "./shiki.config.js"

let highlighter: Awaited<ReturnType<typeof getHighlighter>> | undefined

export const arkHighlight = async (code: string) => {
export type BuiltinLang = "ts" | "bash" | "jsonc"

export type HighlightArgs = {
code: string
lang?: BuiltinLang
}

export const arkHighlight = async (args: HighlightArgs) => {
highlighter ??= await getHighlighter({
themes: [arkdarkColors],
langs: [{ ...arktypeTextmate, name: "ts" } as never]
langs: [{ ...arktypeTextmate, name: "ts" } as never, "bash", "jsonc"]
})
return highlighter.codeToHtml(code, {
lang: "ts",
return highlighter.codeToHtml(args.code, {
lang: args.lang ?? "ts",
theme: "ArkDark",
transformers: [twoslash]
transformers: [twoslash, addCopyButton]
})
}
41 changes: 40 additions & 1 deletion ark/docs/src/components/shiki.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,10 +100,49 @@ export const twoslash = transformerTwoslash({
}
})

const hoverSelector = ".twoslash-popup-code"
const errorSelector = ".twoslash-error-line"
const completionSelector = ".twoslash-completion-cursor"
const metaSelector = `${hoverSelector}, ${errorSelector}, ${completionSelector}`

const distillTwoslashCode = (/** @type {Element} */ container) => {
const walker = document.createTreeWalker(container, NodeFilter.SHOW_TEXT)

let src = ""
while (walker.nextNode()) {
const parentNode = walker.currentNode.parentNode
if (!(parentNode instanceof Element)) continue
if (parentNode.closest(errorSelector)) {
// if a twoslash error was rendered in this position, we need an additional newline
src += "\n"
}
if (!parentNode?.closest(metaSelector)) {
// if the node is not a meta node (hover, error or completion) add its textContent
src += walker.currentNode.textContent ?? ""
}
}

return src.trim()
}

/** @type {import("shiki").ShikiTransformer} */
export const addCopyButton = {
name: "addCopyButton",
postprocess(html) {
return `<div class="code-container">
${html}
<button class="copy-button">
<img class="copy-icon" src= "/src/assets/copy.svg" onload="addCopyButtonListeners()"/>
</button>
</div>`
}
}

/** @type { import("astro").ShikiConfig } */
export const shikiConfig = {
theme: arkdarkColors,
// @ts-expect-error
langs: [arktypeTextmate],
transformers: [twoslash]
transformers: [twoslash, addCopyButton],
wrap: true
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
// @errors: 2322
import { type } from "arktype"
// this file is written in JS so that it can include a syntax error
// without creating a type error while still displaying the error in twoslash
// ---cut---
// hover me
const user = type({
Expand Down
19 changes: 19 additions & 0 deletions ark/docs/src/content/docs/deepIntrospectability.twoslash.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { type } from "arktype"

const user = type({
name: "string",
luckyNumbers: "(number | bigint)[]",
"isAdmin?": "boolean | null"
})

// ---cut---
user.extends("object") // true
user.extends("string") // false
// true (number | bigint is narrower than unknown)
user.extends({
luckyNumbers: "unknown[]"
})
// false (number | bigint is wider than number)
user.extends({
luckyNumbers: "number[]"
})
26 changes: 0 additions & 26 deletions ark/docs/src/content/docs/deepIntrospectability.twoslash.ts

This file was deleted.

Loading

0 comments on commit 1195c09

Please sign in to comment.