Skip to content

Commit

Permalink
Add copy button to Markdown codeblocks (#7451)
Browse files Browse the repository at this point in the history
  • Loading branch information
philippjfr authored Oct 31, 2024
1 parent 8dd362f commit dc2fce3
Show file tree
Hide file tree
Showing 7 changed files with 88 additions and 11 deletions.
3 changes: 1 addition & 2 deletions panel/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,6 @@ module.exports = {
"no-floating-decimal": ["error"],
"no-multiple-empty-lines": ["error", {"max": 1, "maxBOF": 0, "maxEOF": 0}],
"no-new-wrappers": "error",
"no-template-curly-in-string": "error",
"no-throw-literal": "error",
"no-trailing-spaces": ["error"],
"no-var": "error",
Expand Down Expand Up @@ -116,7 +115,7 @@ module.exports = {
"overrides": {},
}],
"guard-for-in": ["warn"],
"quotes": ["error", "double", {"avoidEscape": true, "allowTemplateLiterals": false}],
"quotes": ["error", "double", {"avoidEscape": true, "allowTemplateLiterals": true}],
"curly": ["error", "all"],
"prefer-template": ["error"],
"generator-star-spacing": ["error", {
Expand Down
27 changes: 27 additions & 0 deletions panel/models/html.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
import {ModelEvent, server_event} from "@bokehjs/core/bokeh_events"
import type {StyleSheetLike} from "@bokehjs/core/dom"
import type * as p from "@bokehjs/core/properties"
import type {Attrs, Dict} from "@bokehjs/core/types"
import {entries} from "@bokehjs/core/util/object"
import {Markup} from "@bokehjs/models/widgets/markup"
import {PanelMarkupView} from "./layout"
import {serializeEvent} from "./event-to-object"

import html_css from "styles/models/html.css"

const COPY_ICON = `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-clipboard"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M9 5h-2a2 2 0 0 0 -2 2v12a2 2 0 0 0 2 2h10a2 2 0 0 0 2 -2v-12a2 2 0 0 0 -2 -2h-2" /><path d="M9 3m0 2a2 2 0 0 1 2 -2h2a2 2 0 0 1 2 2v0a2 2 0 0 1 -2 2h-2a2 2 0 0 1 -2 -2z"/></svg>`

const CHECK_ICON = `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-check"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M5 12l5 5l10 -10"/></svg>`

function searchAllDOMs(node: Element | ShadowRoot, selector: string): (Element | ShadowRoot)[] {
let found: (Element | ShadowRoot)[] = []
if (node instanceof Element && node.matches(selector)) {
Expand Down Expand Up @@ -134,6 +141,10 @@ export class HTMLView extends PanelMarkupView {
})
}

override stylesheets(): StyleSheetLike[] {
return [...super.stylesheets(), html_css]
}

protected rerender() {
this.render()
this.invalidate_layout()
Expand All @@ -148,6 +159,22 @@ export class HTMLView extends PanelMarkupView {
run_scripts(this.container)
}
this._setup_event_listeners()
for (const codeblock of this.container.querySelectorAll(".codehilite")) {
const copy_button = document.createElement("button")
const pre = (codeblock.children[0] as HTMLPreElement)
copy_button.className = "copybtn"
copy_button.innerHTML = COPY_ICON
copy_button.addEventListener("click", () => {
const code = pre.innerText
navigator.clipboard.writeText(code).then(() => {
copy_button.innerHTML = CHECK_ICON
setTimeout(() => {
copy_button.innerHTML = COPY_ICON
}, 300)
})
})
codeblock.insertBefore(copy_button, pre)
}
for (const anchor of this.container.querySelectorAll("a")) {
const link = anchor.getAttribute("href")
if (link && link.startsWith("#")) {
Expand Down
33 changes: 33 additions & 0 deletions panel/styles/models/html.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
.copybtn {
position: sticky;
display: flex;
top: 0;
left: 100%;
width: 1.7em;
height: 1.7em;
opacity: 0;
transition: opacity 0.3s, border .3s, background-color .3s;
user-select: none;
padding: 0;
border: none;
outline: none;
border-radius: 0.4em;
border: #1b1f2426 1px solid;
background-color: #f6f8fa;
color: #57606a;
}

.codehilite pre {
margin-top: -1.7em;
}

.copybtn svg {
stroke: currentColor;
width: 1.5em;
height: 1.5em;
padding: 0.1em;
}

.codehilite:hover .copybtn {
opacity: 1;
}
8 changes: 6 additions & 2 deletions panel/theme/css/bootstrap.css
Original file line number Diff line number Diff line change
Expand Up @@ -869,15 +869,19 @@ div .tabulator .tabulator-header .tabulator-col {
}

/* Quill editor */

.ql-editor,
.ql-editor.ql-blank::before {
color: var(--bs-body-color);
}

/* Float panel */

.jsPanel .jsPanel-content {
background-color: var(--bs-body-bg);
color: var(--bs-body-color);
}

/* Copy Button */
.copybtn {
background-color: var(--bs-body-bg);
color: var(--bs-body-color);
}
8 changes: 6 additions & 2 deletions panel/theme/css/fast.css
Original file line number Diff line number Diff line change
Expand Up @@ -1107,7 +1107,6 @@ table.panel-df {
}

/* Quill editor */

.ql-editor {
color: var(--neutral-foreground-rest);
}
Expand All @@ -1117,8 +1116,13 @@ table.panel-df {
}

/* Float panel */

.jsPanel .jsPanel-content {
background-color: var(--background-color);
color: var(--neutral-foreground-rest);
}

/* Copy Button */
.copybtn {
background-color: var(--neutral-fill-input-rest);
color: var(--neutral-foreground-rest);
}
7 changes: 6 additions & 1 deletion panel/theme/css/material.css
Original file line number Diff line number Diff line change
Expand Up @@ -582,8 +582,13 @@ div .tabulator .tabulator-header .tabulator-col {
}

/* Float panel */

.jsPanel .jsPanel-content {
background-color: var(--mdc-theme-background);
color: var(--mdc-theme-on-background);
}

/* Copy Button */
.copybtn {
background-color: var(--mdc-theme-background);
color: var(--mdc-theme-on-background);
}
13 changes: 9 additions & 4 deletions panel/theme/css/native.css
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,12 @@
}

/* Help Icon */

.bk-description > .bk-icon {
background-color: var(--background-text-color);
opacity: 0.4;
}

/* Input widgets */

textarea.bk-input {
padding: 0.5em var(--padding-horizontal);
}
Expand All @@ -68,7 +66,6 @@ textarea.bk-input {
}

/* Quill editor */

.ql-editor,
.ql-editor.ql-blank::before {
color: var(--background-text-color);
Expand All @@ -90,8 +87,16 @@ textarea.bk-input {
}

/* Float panel */

.jsPanel .jsPanel-content {
background-color: var(--background-color);
color: var(--background-text-color);
}

/* Copy Button */
.copybtn {
background-color: #bbb;
}

.copybtn:active {
background-color: #bbb;
}

0 comments on commit dc2fce3

Please sign in to comment.