mirror of
				https://github.com/falsycat/ar.falsy.cat.git
				synced 2025-10-31 05:38:20 +00:00 
			
		
		
		
	Copy to clipboard feature for code block (#152)
Co-authored-by: Jacky Zhao <j.zhao2k19@gmail.com>
This commit is contained in:
		
							
								
								
									
										38
									
								
								assets/js/clipboard.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								assets/js/clipboard.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,38 @@ | ||||
| const svgCopy = | ||||
|     '<svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true"><path fill-rule="evenodd" d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 010 1.5h-1.5a.25.25 0 00-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 00.25-.25v-1.5a.75.75 0 011.5 0v1.5A1.75 1.75 0 019.25 16h-7.5A1.75 1.75 0 010 14.25v-7.5z"></path><path fill-rule="evenodd" d="M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0114.25 11h-7.5A1.75 1.75 0 015 9.25v-7.5zm1.75-.25a.25.25 0 00-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 00.25-.25v-7.5a.25.25 0 00-.25-.25h-7.5z"></path></svg>'; | ||||
| const svgCheck = | ||||
|     '<svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true"><path fill-rule="evenodd" fill="rgb(63, 185, 80)" d="M13.78 4.22a.75.75 0 010 1.06l-7.25 7.25a.75.75 0 01-1.06 0L2.22 9.28a.75.75 0 011.06-1.06L6 10.94l6.72-6.72a.75.75 0 011.06 0z"></path></svg>'; | ||||
|  | ||||
|  | ||||
| const addCopyButtons = () => { | ||||
|     let els = document.getElementsByClassName("highlight"); | ||||
|     // for each highlight | ||||
|     for (let i = 0; i < els.length; i++) { | ||||
|         if (els[i].getElementsByClassName("clipboard-button").length) continue; | ||||
|  | ||||
|         // find pre > code inside els[i] | ||||
|         let codeBlocks = els[i].getElementsByTagName("code"); | ||||
|  | ||||
|          // line numbers are inside first code block | ||||
|         let lastCodeBlock = codeBlocks[codeBlocks.length - 1]; | ||||
|         const button = document.createElement("button"); | ||||
|         button.className = "clipboard-button"; | ||||
|         button.type = "button"; | ||||
|         button.innerHTML = svgCopy; | ||||
|         // remove every second newline from lastCodeBlock.innerText | ||||
|         button.addEventListener("click", () => { | ||||
|             navigator.clipboard.writeText(lastCodeBlock.innerText.replace(/\n\n/g, "\n")).then( | ||||
|                 () => { | ||||
|                     button.blur(); | ||||
|                     button.innerHTML = svgCheck; | ||||
|                     setTimeout(() => (button.innerHTML = svgCopy), 2000); | ||||
|                 }, | ||||
|                 (error) => (button.innerHTML = "Error") | ||||
|             ); | ||||
|         }); | ||||
|         // find chroma inside els[i] | ||||
|         let chroma = els[i].getElementsByClassName("chroma")[0]; | ||||
|         els[i].insertBefore(button, chroma); | ||||
|         console.log(els[i].lastChild) | ||||
|     } | ||||
| } | ||||
| @@ -8,7 +8,7 @@ const syntaxTheme = document.querySelector("#theme-link"); | ||||
|  | ||||
| if (currentTheme) { | ||||
|   document.documentElement.setAttribute('saved-theme', currentTheme); | ||||
|   (currentTheme === 'dark') ? syntaxTheme.href = '{{ $darkSyntax.Permalink }}' : syntaxTheme.href = '{{ $lightSyntax.Permalink }}'; | ||||
|   syntaxTheme.href = currentTheme === 'dark' ?  '{{ $darkSyntax.Permalink }}' :  '{{ $lightSyntax.Permalink }}'; | ||||
| } | ||||
|  | ||||
| const switchTheme = (e) => { | ||||
|   | ||||
							
								
								
									
										47
									
								
								assets/styles/clipboard.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								assets/styles/clipboard.scss
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,47 @@ | ||||
| .clipboard-button { | ||||
|   position: absolute; | ||||
|   display: flex; | ||||
|   float: right; | ||||
|   right: 0; | ||||
|   padding: 0.69em; | ||||
|   margin: 0.5em; | ||||
|   color: var(--outlinegray); | ||||
|   border-color: var(--dark); | ||||
|   background-color: var(--lightgray); | ||||
|   filter: contrast(1.1); | ||||
|   border: 2px solid; | ||||
|   border-radius: 6px; | ||||
|   font-size: 0.8em; | ||||
|   z-index: 1; | ||||
|   opacity: 0; | ||||
|   transition: 0.12s; | ||||
|    | ||||
|   & > svg { | ||||
|     fill: var(--light); | ||||
|     filter: contrast(0.3); | ||||
|   } | ||||
|    | ||||
|   &:hover { | ||||
|     cursor: pointer; | ||||
|     border-color: var(--primary); | ||||
|      | ||||
|     & > svg { | ||||
|       fill: var(--primary); | ||||
|     } | ||||
|   } | ||||
|    | ||||
|   &:focus { | ||||
|     outline: 0; | ||||
|   } | ||||
| } | ||||
|  | ||||
| .highlight { | ||||
|   position: relative; | ||||
|    | ||||
|   &:hover > .clipboard-button { | ||||
|     opacity: 1; | ||||
|     transition: 0.2s; | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| @@ -28,12 +28,15 @@ enableLinkPreview: true | ||||
| # whether to render titles for code blocks | ||||
| enableCodeBlockTitle: true  | ||||
|  | ||||
| # whether to render copy buttons for code blocks | ||||
| enableCodeBlockCopy: true  | ||||
|  | ||||
| # whether to try to process Latex | ||||
| enableLatex: true | ||||
|  | ||||
| # whether to enable single-page-app style rendering | ||||
| # this prevents flahses of unstyled content and overall improves | ||||
| # smoothness of quartz. More info in issue #109 on GitHub | ||||
| # this prevents flashes of unstyled content and improves | ||||
| # smoothness of Quartz. More info in issue #109 on GitHub | ||||
| enableSPA: true | ||||
|  | ||||
| # whether to render a footer | ||||
| @@ -83,10 +86,10 @@ To add code block titles with Quartz: | ||||
|       ``` | ||||
|  | ||||
| **Note** that if `{title=<my-title>}` is included, and code block titles are not | ||||
| enabled, no errors will occur and the title attribute will be ignored. | ||||
| enabled, no errors will occur, and the title attribute will be ignored. | ||||
|  | ||||
| ### HTML Favicons | ||||
| If you would like to customize the favicons of your quartz-based website, you  | ||||
| If you would like to customize the favicons of your Quartz-based website, you  | ||||
| can add them to the `data/config.yaml` file. The **default** without any set  | ||||
| `favicon` key is: | ||||
|  | ||||
| @@ -95,7 +98,7 @@ can add them to the `data/config.yaml` file. The **default** without any set | ||||
| ``` | ||||
|  | ||||
| The default can be overridden by defining a value to the `favicon` key in your  | ||||
| `data/config.yaml` file. Here is a `List[Dictionary]` example format, which is | ||||
| `data/config.yaml` file. For example, here is a `List[Dictionary]` example format, which is | ||||
| equivalent to the default: | ||||
|  | ||||
| ```yaml {title="data/config.yaml", linenos=false} | ||||
| @@ -108,7 +111,7 @@ In this format, the keys are identical to their HTML representations. | ||||
|  | ||||
| If you plan to add multiple favicons generated by a website (see list below), it | ||||
| may be easier to define it as HTML. Here is an example which appends the  | ||||
| **Apple touch icon** to quartz's default favicon: | ||||
| **Apple touch icon** to Quartz's default favicon: | ||||
|  | ||||
| ```yaml {title="data/config.yaml", linenos=false} | ||||
| favicon: | | ||||
| @@ -118,7 +121,7 @@ favicon: | | ||||
|  | ||||
| This second favicon will now be used as a web page icon when someone adds your  | ||||
| webpage to the home screen of their Apple device. If you are interested in more  | ||||
| information about the current, and past, standards of favicons, you can read  | ||||
| information about the current and past standards of favicons, you can read  | ||||
| [this article](https://www.emergeinteractive.com/insights/detail/the-essentials-of-favicons/). | ||||
|  | ||||
| **Note** that all generated favicon paths, defined by the `href`  | ||||
| @@ -136,7 +139,7 @@ enableGlobalGraph: false | ||||
|  | ||||
| ### Local Graph ### | ||||
| localGraph: | ||||
| 	# whether automatically generate a legend | ||||
|     # whether automatically generate a legend | ||||
|     enableLegend: false | ||||
|      | ||||
|     # whether to allow dragging nodes in the graph | ||||
| @@ -181,7 +184,7 @@ paths: | ||||
| Want to go even more in-depth? You can add custom CSS styling and change existing colours through editing `assets/styles/custom.scss`. If you'd like to target specific parts of the site, you can add ids and classes to the HTML partials in `/layouts/partials`.  | ||||
|  | ||||
| ### Partials | ||||
| Partials are what dictate what actually gets rendered to the page. Want to change how pages are styled and structured? You can edit the appropriate layout in `/layouts`. | ||||
| Partials are what dictate what gets rendered to the page. Want to change how pages are styled and structured? You can edit the appropriate layout in `/layouts`. | ||||
|  | ||||
| For example, the structure of the home page can be edited through `/layouts/index.html`. To customize the footer, you can edit `/layouts/partials/footer.html` | ||||
|  | ||||
|   | ||||
| @@ -4,6 +4,7 @@ openToc: false | ||||
| enableLinkPreview: true | ||||
| enableLatex: true | ||||
| enableCodeBlockTitle: true | ||||
| enableCodeBlockCopy: true | ||||
| enableSPA: true | ||||
| enableFooter: true | ||||
| enableContextualBacklinks: true | ||||
|   | ||||
| @@ -54,6 +54,13 @@ | ||||
|   <script src="{{$codeTitle.Permalink}}"></script> | ||||
|   {{end}} | ||||
|  | ||||
|   {{ if $.Site.Data.config.enableCodeBlockCopy }} | ||||
|   {{ $clipboard := resources.Get "js/clipboard.js" | resources.Fingerprint "md5" | resources.Minify }} | ||||
|   {{ if (findRE "<pre" .Content 1) }} | ||||
|     <script src="{{$clipboard.Permalink}}"></script> | ||||
|   {{ end }} | ||||
|   {{ end }} | ||||
|  | ||||
|   <!--  Preload page vars  --> | ||||
|   {{$linkIndex := resources.Get "indices/linkIndex.json" | resources.Fingerprint | ||||
|   "md5" | resources.Minify | }} {{$contentIndex := resources.Get | ||||
| @@ -85,6 +92,10 @@ | ||||
|       const pathWindow = window.location.pathname; | ||||
|       const isHome = pathBase == pathWindow; | ||||
|  | ||||
|       {{if $.Site.Data.config.enableCodeBlockCopy -}} | ||||
|       addCopyButtons(); | ||||
|       {{ end }} | ||||
|  | ||||
|       {{if $.Site.Data.config.enableSPA -}} | ||||
|       addTitleToCodeBlocks(); | ||||
|       {{ end }} | ||||
| @@ -118,12 +129,12 @@ | ||||
|  | ||||
|     const init = (doc = document) => { | ||||
|       // NOTE: everything within this callback will be executed for initial page navigation. This is a good place to put JavaScript that only replaces DOM nodes. | ||||
|       {{if $.Site.Data.config.enableCodeBlockCopy -}} | ||||
|       addCopyButtons(); | ||||
|       {{ end }} | ||||
|  | ||||
|       {{if $.Site.Data.config.enableCodeBlockTitle -}} | ||||
|       {{if $.Site.Data.config.enableSPA -}} | ||||
|       addTitleToCodeBlocks(); | ||||
|       {{ else }} | ||||
|       window.addEventListener("DOMContentLoaded", addTitleToCodeBlocks); | ||||
|       {{- end -}} | ||||
|       {{- end -}} | ||||
|       {{if $.Site.Data.config.enableLatex}} | ||||
|       renderMathInElement(doc.body, { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user