Skip to content

Commit

Permalink
feat: allow enable/disable code block copy button (#331)
Browse files Browse the repository at this point in the history
* refactor: move codeblock to a partial component

* feat: add flags for code block copy button

* allow disable code copy button completely
* allow make the copy button always visible

* chore: run build:css
  • Loading branch information
imfing authored Mar 28, 2024
1 parent 741a640 commit d8351aa
Show file tree
Hide file tree
Showing 9 changed files with 76 additions and 59 deletions.
60 changes: 30 additions & 30 deletions assets/css/compiled/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -1545,7 +1545,7 @@ video {
--tw-text-opacity: 1;
color: rgb(156 163 175 / var(--tw-text-opacity));
}
.content :where(pre):not(:where(.code-block pre, [class~=not-prose],[class~=not-prose] *)) {
.content :where(pre):not(:where(.hextra-code-block pre, [class~=not-prose],[class~=not-prose] *)) {
margin-bottom: 1rem;
overflow-x: auto;
border-radius: 0.75rem;
Expand All @@ -1559,23 +1559,23 @@ video {
}
@media (prefers-contrast: more) {

.content :where(pre):not(:where(.code-block pre, [class~=not-prose],[class~=not-prose] *)) {
.content :where(pre):not(:where(.hextra-code-block pre, [class~=not-prose],[class~=not-prose] *)) {
border-width: 1px;
border-color: hsl(var(--primary-hue) var(--primary-saturation) 24% / 0.2);
--tw-contrast: contrast(1.5);
filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
}
}
:is(html[class~="dark"] .content :where(pre):not(:where(.code-block pre, [class~=not-prose],[class~=not-prose] *))) {
:is(html[class~="dark"] .content :where(pre):not(:where(.hextra-code-block pre, [class~=not-prose],[class~=not-prose] *))) {
background-color: hsl(var(--primary-hue) var(--primary-saturation) 77% / 0.1);
}
@media (prefers-contrast: more) {

:is(html[class~="dark"] .content :where(pre):not(:where(.code-block pre, [class~=not-prose],[class~=not-prose] *))) {
:is(html[class~="dark"] .content :where(pre):not(:where(.hextra-code-block pre, [class~=not-prose],[class~=not-prose] *))) {
border-color: hsl(var(--primary-hue) var(--primary-saturation) 94% / 0.4);
}
}
.content :where(code):not(:where(.code-block code, [class~=not-prose],[class~=not-prose] *)) {
.content :where(code):not(:where(.hextra-code-block code, [class~=not-prose],[class~=not-prose] *)) {
overflow-wrap: break-word;
border-radius: 0.375rem;
border-width: 1px;
Expand All @@ -1589,38 +1589,38 @@ video {
padding-right: .25em;
font-size: .9em;
}
:is(html[class~="dark"] .content :where(code):not(:where(.code-block code, [class~=not-prose],[class~=not-prose] *))) {
:is(html[class~="dark"] .content :where(code):not(:where(.hextra-code-block code, [class~=not-prose],[class~=not-prose] *))) {
border-color: rgb(255 255 255 / 0.1);
background-color: rgb(255 255 255 / 0.1);
}
.content :where(table):not(:where(.code-block table, [class~=not-prose],[class~=not-prose] *)) {
.content :where(table):not(:where(.hextra-code-block table, [class~=not-prose],[class~=not-prose] *)) {
margin-top: 1.5rem;
display: block;
overflow-x: auto;
padding: 0px;
}
.content :where(table):not(:where(.code-block table, [class~=not-prose],[class~=not-prose] *)):first-child {
.content :where(table):not(:where(.hextra-code-block table, [class~=not-prose],[class~=not-prose] *)):first-child {
margin-top: 0px;
}
.content :where(table):not(:where(.code-block table, [class~=not-prose],[class~=not-prose] *)) tr {
.content :where(table):not(:where(.hextra-code-block table, [class~=not-prose],[class~=not-prose] *)) tr {
margin: 0px;
border-top-width: 1px;
--tw-border-opacity: 1;
border-color: rgb(209 213 219 / var(--tw-border-opacity));
padding: 0px;
}
.content :where(table):not(:where(.code-block table, [class~=not-prose],[class~=not-prose] *)) tr:nth-child(even) {
.content :where(table):not(:where(.hextra-code-block table, [class~=not-prose],[class~=not-prose] *)) tr:nth-child(even) {
--tw-bg-opacity: 1;
background-color: rgb(243 244 246 / var(--tw-bg-opacity));
}
:is(html[class~="dark"] .content :where(table):not(:where(.code-block table, [class~=not-prose],[class~=not-prose] *)) tr) {
:is(html[class~="dark"] .content :where(table):not(:where(.hextra-code-block table, [class~=not-prose],[class~=not-prose] *)) tr) {
--tw-border-opacity: 1;
border-color: rgb(75 85 99 / var(--tw-border-opacity));
}
:is(html[class~="dark"] .content :where(table):not(:where(.code-block table, [class~=not-prose],[class~=not-prose] *)) tr):nth-child(even) {
:is(html[class~="dark"] .content :where(table):not(:where(.hextra-code-block table, [class~=not-prose],[class~=not-prose] *)) tr):nth-child(even) {
background-color: rgb(75 85 99 / 0.2);
}
.content :where(table):not(:where(.code-block table, [class~=not-prose],[class~=not-prose] *)) th {
.content :where(table):not(:where(.hextra-code-block table, [class~=not-prose],[class~=not-prose] *)) th {
margin: 0px;
border-width: 1px;
--tw-border-opacity: 1;
Expand All @@ -1631,11 +1631,11 @@ video {
padding-bottom: 0.5rem;
font-weight: 600;
}
:is(html[class~="dark"] .content :where(table):not(:where(.code-block table, [class~=not-prose],[class~=not-prose] *)) th) {
:is(html[class~="dark"] .content :where(table):not(:where(.hextra-code-block table, [class~=not-prose],[class~=not-prose] *)) th) {
--tw-border-opacity: 1;
border-color: rgb(75 85 99 / var(--tw-border-opacity));
}
.content :where(table):not(:where(.code-block table, [class~=not-prose],[class~=not-prose] *)) td {
.content :where(table):not(:where(.hextra-code-block table, [class~=not-prose],[class~=not-prose] *)) td {
margin: 0px;
border-width: 1px;
--tw-border-opacity: 1;
Expand All @@ -1645,7 +1645,7 @@ video {
padding-top: 0.5rem;
padding-bottom: 0.5rem;
}
:is(html[class~="dark"] .content :where(table):not(:where(.code-block table, [class~=not-prose],[class~=not-prose] *)) td) {
:is(html[class~="dark"] .content :where(table):not(:where(.hextra-code-block table, [class~=not-prose],[class~=not-prose] *)) td) {
--tw-border-opacity: 1;
border-color: rgb(75 85 99 / var(--tw-border-opacity));
}
Expand Down Expand Up @@ -1707,11 +1707,11 @@ video {
border-color: rgb(255 255 255 / 0.1);
background-color: rgb(255 255 255 / 0.1);
}
.content :where(pre.mermaid):not(:where(.code-block pre, [class~=not-prose],[class~=not-prose] *)) {
.content :where(pre.mermaid):not(:where(.hextra-code-block pre, [class~=not-prose],[class~=not-prose] *)) {
border-radius: 0px;
background-color: transparent;
}
:is(html[class~="dark"] .content :where(pre.mermaid):not(:where(.code-block pre, [class~=not-prose],[class~=not-prose] *))) {
:is(html[class~="dark"] .content :where(pre.mermaid):not(:where(.hextra-code-block pre, [class~=not-prose],[class~=not-prose] *))) {
background-color: transparent;
}
.content :where(img):not(:where([class~=not-prose],[class~=not-prose] *)) {
Expand Down Expand Up @@ -2117,11 +2117,11 @@ article details > summary::before {
.dark .highlight .chroma .gl { text-decoration: underline }
/* TextWhitespace */
.dark .highlight .chroma .w { color: #6e7681 }
.code-block {
.hextra-code-block {
font-size: .9em;
line-height: 1.25rem;
}
.code-block pre {
.hextra-code-block pre {
overflow-x: auto;
background-color: hsl(var(--primary-hue) var(--primary-saturation) 39% / 0.05);
font-size: .9em;
Expand All @@ -2131,23 +2131,23 @@ article details > summary::before {
}
@media (prefers-contrast: more) {

.code-block pre {
.hextra-code-block pre {
border-width: 1px;
border-color: hsl(var(--primary-hue) var(--primary-saturation) 24% / 0.2);
--tw-contrast: contrast(1.5);
filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
}
}
:is(html[class~="dark"] .code-block pre) {
:is(html[class~="dark"] .hextra-code-block pre) {
background-color: hsl(var(--primary-hue) var(--primary-saturation) 77% / 0.1);
}
@media (prefers-contrast: more) {

:is(html[class~="dark"] .code-block pre) {
:is(html[class~="dark"] .hextra-code-block pre) {
border-color: hsl(var(--primary-hue) var(--primary-saturation) 94% / 0.4);
}
}
.code-block .filename {
.hextra-code-block .filename {
position: absolute;
top: 0px;
z-index: 1;
Expand All @@ -2166,24 +2166,24 @@ article details > summary::before {
--tw-text-opacity: 1;
color: rgb(55 65 81 / var(--tw-text-opacity));
}
:is(html[class~="dark"] .code-block .filename) {
:is(html[class~="dark"] .hextra-code-block .filename) {
background-color: hsl(var(--primary-hue) var(--primary-saturation) 77% / 0.1);
--tw-text-opacity: 1;
color: rgb(229 231 235 / var(--tw-text-opacity));
}
.code-block .filename + pre:not(.lntable pre) {
.hextra-code-block .filename + pre:not(.lntable pre) {
/* Override padding for code blocks with filename but no highlight */
padding-top: 3rem;
}
.code-block pre:not(.lntable pre) {
.hextra-code-block pre:not(.lntable pre) {
margin-bottom: 1rem;
border-radius: 0.75rem;
padding-left: 1rem;
padding-right: 1rem;
padding-top: 1rem;
padding-bottom: 1rem;
}
.code-block div:nth-of-type(2) pre {
.hextra-code-block div:nth-of-type(2) pre {
padding-top: 3rem;
padding-bottom: 1rem;
}
Expand Down Expand Up @@ -2542,13 +2542,13 @@ nav .search-wrapper {
@supports (
((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px)))
) {
.code-copy-btn {
.hextra-hextra-code-copy-btn {
--tw-bg-opacity: .85;
--tw-backdrop-blur: blur(12px);
-webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);
backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);
}
:is(html[class~="dark"] .code-copy-btn) {
:is(html[class~="dark"] .hextra-hextra-code-copy-btn) {
--tw-bg-opacity: 0.8;
}
}
Expand Down
2 changes: 1 addition & 1 deletion assets/css/components/code-copy.css
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
@supports (
(-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))
) {
.code-copy-btn {
.hextra-hextra-code-copy-btn {
@apply hx-backdrop-blur-md hx-bg-opacity-[.85] dark:hx-bg-opacity-80;
}
}
6 changes: 3 additions & 3 deletions assets/css/highlight.css
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
@import "chroma/light.css";
@import "chroma/dark.css";

.code-block {
.hextra-code-block {
@apply hx-text-[.9em] hx-leading-5;

pre {
Expand All @@ -19,11 +19,11 @@
}
}

.code-block pre:not(.lntable pre) {
.hextra-code-block pre:not(.lntable pre) {
@apply hx-px-4 hx-mb-4 hx-py-4 hx-rounded-xl;
}

.code-block div:nth-of-type(2) pre {
.hextra-code-block div:nth-of-type(2) pre {
@apply hx-pt-12 hx-pb-4;
}

Expand Down
8 changes: 4 additions & 4 deletions assets/css/typography.css
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,13 @@
:where(blockquote):not(:where([class~=not-prose],[class~=not-prose] *)) {
@apply hx-mt-6 hx-border-gray-300 hx-italic hx-text-gray-700 dark:hx-border-gray-700 dark:hx-text-gray-400 first:hx-mt-0 ltr:hx-border-l-2 ltr:hx-pl-6 rtl:hx-border-r-2 rtl:hx-pr-6;
}
:where(pre):not(:where(.code-block pre, [class~=not-prose],[class~=not-prose] *)) {
:where(pre):not(:where(.hextra-code-block pre, [class~=not-prose],[class~=not-prose] *)) {
@apply hx-bg-primary-700/5 hx-mb-4 hx-overflow-x-auto hx-rounded-xl hx-font-medium hx-subpixel-antialiased dark:hx-bg-primary-300/10 hx-text-[.9em] contrast-more:hx-border contrast-more:hx-border-primary-900/20 contrast-more:hx-contrast-150 contrast-more:dark:hx-border-primary-100/40 hx-py-4;
}
:where(code):not(:where(.code-block code, [class~=not-prose],[class~=not-prose] *)) {
:where(code):not(:where(.hextra-code-block code, [class~=not-prose],[class~=not-prose] *)) {
@apply hx-border-black hx-border-opacity-[0.04] hx-bg-opacity-[0.03] hx-bg-black hx-break-words hx-rounded-md hx-border hx-py-0.5 hx-px-[.25em] hx-text-[.9em] dark:hx-border-white/10 dark:hx-bg-white/10;
}
:where(table):not(:where(.code-block table, [class~=not-prose],[class~=not-prose] *)) {
:where(table):not(:where(.hextra-code-block table, [class~=not-prose],[class~=not-prose] *)) {
@apply hx-block hx-overflow-x-auto hx-mt-6 hx-p-0 first:hx-mt-0;

tr {
Expand Down Expand Up @@ -66,7 +66,7 @@
:where(kbd):not(:where([class~=not-prose],[class~=not-prose] *)) {
@apply hx-border-black hx-border-opacity-[0.04] hx-bg-opacity-[0.03] hx-bg-black hx-break-words hx-rounded-md hx-border hx-py-0.5 hx-px-[.25em] hx-text-[.9em] dark:hx-border-white/10 dark:hx-bg-white/10;
}
:where(pre.mermaid):not(:where(.code-block pre, [class~=not-prose],[class~=not-prose] *)) {
:where(pre.mermaid):not(:where(.hextra-code-block pre, [class~=not-prose],[class~=not-prose] *)) {
@apply hx-bg-transparent hx-rounded-none dark:hx-bg-transparent;
}
:where(img):not(:where([class~=not-prose],[class~=not-prose] *)) {
Expand Down
2 changes: 1 addition & 1 deletion assets/js/code-copy.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ document.addEventListener('DOMContentLoaded', function () {
return svg;
}

document.querySelectorAll('.code-copy-btn').forEach(function (button) {
document.querySelectorAll('.hextra-code-copy-btn').forEach(function (button) {
// Add copy and success icons
button.querySelector('.copy-icon')?.appendChild(getCopyIcon());
button.querySelector('.success-icon')?.appendChild(getSuccessIcon());
Expand Down
4 changes: 3 additions & 1 deletion exampleSite/hugo_stats.json
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,6 @@
"before:hx-transition-transform",
"before:hx-w-px",
"chroma",
"code-block",
"code-copy-btn",
"content",
"contrast-more:dark:hover:hx-border-gray-50",
Expand Down Expand Up @@ -211,6 +210,9 @@
"hamburger-menu",
"hextra-card",
"hextra-cards",
"hextra-code-block",
"hextra-code-copy-btn",
"hextra-code-copy-btn-container",
"hextra-feature-card",
"hextra-filetree",
"hextra-filetree-folder",
Expand Down
25 changes: 6 additions & 19 deletions layouts/_default/_markup/render-codeblock.html
Original file line number Diff line number Diff line change
@@ -1,25 +1,12 @@
{{- $class := .Attributes.class | default "" -}}
{{- $filename := .Attributes.filename | default "" -}}
{{- $lang := .Attributes.lang | default .Type -}}
{{- $copyCode := (T "copyCode") | default "Copy code" -}}


<div class="code-block hx-relative hx-mt-6 first:hx-mt-0 hx-group/code">
{{- if $filename -}}
<div class="filename" dir="auto">{{ $filename }}</div>
{{- end -}}
{{- if transform.CanHighlight $lang -}}
<div>{{- highlight .Inner $lang .Options -}}</div>
{{- else -}}
<pre><code>{{ .Inner }}</code></pre>
{{- end -}}
<div class="hx-opacity-0 hx-transition group-hover/code:hx-opacity-100 hx-flex hx-gap-1 hx-absolute hx-m-[11px] hx-right-0 {{ if $filename }}hx-top-8{{ else }}hx-top-0{{ end }}">
<button
class="code-copy-btn hx-group/copybtn hx-transition-all active:hx-opacity-50 hx-bg-primary-700/5 hx-border hx-border-black/5 hx-text-gray-600 hover:hx-text-gray-900 hx-rounded-md hx-p-1.5 dark:hx-bg-primary-300/10 dark:hx-border-white/10 dark:hx-text-gray-400 dark:hover:hx-text-gray-50"
title="{{ $copyCode }}"
>
<div class="copy-icon group-[.copied]/copybtn:hx-hidden hx-pointer-events-none hx-h-4 hx-w-4"></div>
<div class="success-icon hx-hidden group-[.copied]/copybtn:hx-block hx-pointer-events-none hx-h-4 hx-w-4"></div>
</button>
</div>
<div class="hextra-code-block hx-relative hx-mt-6 first:hx-mt-0 hx-group/code">
{{ partial "components/codeblock" (dict "filename" $filename "lang" $lang "content" .Inner "options" .Options) }}

{{- if or (eq site.Params.highlight.copy.enable nil) (site.Params.highlight.copy.enable) }}
{{- partialCached "components/codeblock-copy-button" (dict "filename" $filename) $filename }}
{{ end }}
</div>
15 changes: 15 additions & 0 deletions layouts/partials/components/codeblock-copy-button.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{{/* TODO: remove filename variable */}}
{{- $filename := .filename | default "" -}}
{{- $display := site.Params.highlight.copy.display | default "hover" -}}
{{- $copyCode := (T "copyCode") | default "Copy code" -}}


<div class="hextra-code-copy-btn-container {{ if eq $display `hover` }}hx-opacity-0{{ end }} hx-transition group-hover/code:hx-opacity-100 hx-flex hx-gap-1 hx-absolute hx-m-[11px] hx-right-0 {{ if $filename }}hx-top-8{{ else }}hx-top-0{{ end }}">
<button
class="hextra-code-copy-btn hx-group/copybtn hx-transition-all active:hx-opacity-50 hx-bg-primary-700/5 hx-border hx-border-black/5 hx-text-gray-600 hover:hx-text-gray-900 hx-rounded-md hx-p-1.5 dark:hx-bg-primary-300/10 dark:hx-border-white/10 dark:hx-text-gray-400 dark:hover:hx-text-gray-50"
title="{{ $copyCode }}"
>
<div class="copy-icon group-[.copied]/copybtn:hx-hidden hx-pointer-events-none hx-h-4 hx-w-4"></div>
<div class="success-icon hx-hidden group-[.copied]/copybtn:hx-block hx-pointer-events-none hx-h-4 hx-w-4"></div>
</button>
</div>
13 changes: 13 additions & 0 deletions layouts/partials/components/codeblock.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{{ $filename := .filename | default "" -}}
{{ $lang := .lang | default "" }}
{{ $content := .content }}
{{ $options := .options | default (dict) }}

{{- if $filename -}}
<div class="filename" dir="auto">{{ $filename }}</div>
{{- end -}}
{{- if transform.CanHighlight $lang -}}
<div>{{- highlight $content $lang $options -}}</div>
{{- else -}}
<pre><code>{{ $content }}</code></pre>
{{- end -}}

0 comments on commit d8351aa

Please sign in to comment.