Shaku makes it super easy to annotate code with special directives in comments.
const Hello = "World!"// ^// [Hello World!]
const Hello = "World!"// ^// [Hello World!]
Above code is already self-explanatory, but with Shaku it is rendered into sth even better.
const Hello = "World!"Hello World!
const Hello = "World!"Hello World!
Now code and annotation are visually separated, super cool to explain code, right?
Choose the right tool for your use case.
Also some demos you can refer to:
Or you can just inspect the source code of this website - CodeBlock.tsx
, CodePreviewRemark.tsx
or CodePreviewMarked.tsx
Shaku supports most languages that are supported by Shiki. You can find the +150 languages from Shaku Snippet.
Shaku renders code into a <pre />
with class.shaku
, and shaku elements have class names prefixed with .shaku
, you can use the CSS from this website and adapt to your needs.
The class names for each Shaku element will be explained in Syntax section.
You can render multiple themes by setting themes
in the Shaku plugins, the theme lang is put on the <pre>
tag. Thus we can control the visibility by CSS
const marked = new Marked();marked.use(markedShakuCodeAnnotate({themes: ["github-light", "github-dark"],langs: ["javascript", "css", "jsx", "html", "typescript", "tsx"],}));
const marked = new Marked();marked.use(markedShakuCodeAnnotate({themes: ["github-light", "github-dark"],langs: ["javascript", "css", "jsx", "html", "typescript", "tsx"],}));
pre.shaku.github-dark {display: none;}@media (prefers-color-scheme: dark) {pre.shaku.github-dark {display: block;}pre.shaku.github-light {display: none;}}
pre.shaku.github-dark {display: none;}@media (prefers-color-scheme: dark) {pre.shaku.github-dark {display: block;}pre.shaku.github-light {display: none;}}
You can also try out the syntax on Shaku Playground or Shaku Snippet.
const blog = "https://jser.dev"JSer.dev is the homepage for JSer.
Check it out! jser.dev
// This is a normal comment
const blog = "https://jser.dev"JSer.dev is the homepage for JSer.
Check it out! jser.dev
// This is a normal comment
Place ^
for the arrow, and []
for the text, you can also enable basic markdown support.
const blog = "https://jser.dev"// ^// [JSer.dev is the *homepage* for JSer.]// [Check it out! [jser.dev](https://jser.dev)]// This is a normal comment
const blog = "https://jser.dev"// ^// [JSer.dev is the *homepage* for JSer.]// [Check it out! [jser.dev](https://jser.dev)]// This is a normal comment
.shaku-callout
and .shaku-callout-arrow
are used to style callout.
.shaku-callout {background-color: var(--color-shaku-callout-light, #0685ce);color: #fff;padding: 0.5em 1ch;position: relative;margin: 0.5em 0 0 -0.2ch;display: inline-block;border-radius: 2px;}.shaku-callout-arrow {width: 1ch;height: 1ch;display: inline-block;background-color: var(--color-shaku-callout-light, #0685ce);position: absolute;top: -0.5ch;transform: rotate(45deg);margin-left: 0.2ch;}
.shaku-callout {background-color: var(--color-shaku-callout-light, #0685ce);color: #fff;padding: 0.5em 1ch;position: relative;margin: 0.5em 0 0 -0.2ch;display: inline-block;border-radius: 2px;}.shaku-callout-arrow {width: 1ch;height: 1ch;display: inline-block;background-color: var(--color-shaku-callout-light, #0685ce);position: absolute;top: -0.5ch;transform: rotate(45deg);margin-left: 0.2ch;}
// This is normal comments from source code.const blog = "https://jser.dev"const blog = "jser.dev"--------const blog = "jser.dev"~~~~~~~~const blog = "jser.dev"........
// This is normal comments from source code.const blog = "https://jser.dev"const blog = "jser.dev"--------const blog = "jser.dev"~~~~~~~~const blog = "jser.dev"........
Simply use -----
, ....
, ~~~~~
for underlines.
// This is normal comments from source code.const blog = "https://jser.dev"// ----------------// [JSer.dev is the **homepage** for JSer.]// [Check it out! [jser.dev](https://jser.dev)]const blog = "jser.dev"// --------const blog = "jser.dev"// ~~~~~~~~const blog = "jser.dev"// ........
// This is normal comments from source code.const blog = "https://jser.dev"// ----------------// [JSer.dev is the **homepage** for JSer.]// [Check it out! [jser.dev](https://jser.dev)]const blog = "jser.dev"// --------const blog = "jser.dev"// ~~~~~~~~const blog = "jser.dev"// ........
.shaku-underline
is the base style, .shaku-underline-wavy
, .shaku-underline-solid
and .shaku-underline-dotted
are for the variations.
.shaku-underline {padding: 0 1ch;position: relative;display: block;border-radius: 3px;color: var(--color-shaku-underline-light, red);margin: 0;width: min-content;}.shaku-underline-line {line-height: 0;top: 0.5em;position: absolute;text-decoration-line: overline;text-decoration-color: var(--color-shaku-underline-light, red);color: transparent;pointer-events: none;user-select: none;text-decoration-thickness: 2px;}.shaku-underline-wavy > .shaku-underline-line {text-decoration-style: wavy;top: 0.7em;}.shaku-underline-solid > .shaku-underline-line {text-decoration-style: solid;}.shaku-underline-dotted > .shaku-underline-line {text-decoration-style: dotted;}
.shaku-underline {padding: 0 1ch;position: relative;display: block;border-radius: 3px;color: var(--color-shaku-underline-light, red);margin: 0;width: min-content;}.shaku-underline-line {line-height: 0;top: 0.5em;position: absolute;text-decoration-line: overline;text-decoration-color: var(--color-shaku-underline-light, red);color: transparent;pointer-events: none;user-select: none;text-decoration-thickness: 2px;}.shaku-underline-wavy > .shaku-underline-line {text-decoration-style: wavy;top: 0.7em;}.shaku-underline-solid > .shaku-underline-line {text-decoration-style: solid;}.shaku-underline-dotted > .shaku-underline-line {text-decoration-style: dotted;}
function useSomeEffect({blog}) {useEffect(() => {// do some stuffreturn () => {location.href = 'https://jser.dev'}}, [blog])}
function useSomeEffect({blog}) {useEffect(() => {// do some stuffreturn () => {location.href = 'https://jser.dev'}}, [blog])}
Use @highlight
to highlight next line, @highlight start
and@highlight end
for multiple lines.
// @highlightfunction useSomeEffect({blog}) {useEffect(() => {// do some stuff// @highlight startreturn () => {location.href = 'https://jser.dev'}// @highlight end}, [blog])}
// @highlightfunction useSomeEffect({blog}) {useEffect(() => {// do some stuff// @highlight startreturn () => {location.href = 'https://jser.dev'}// @highlight end}, [blog])}
.shaku .line.highlight
could be used to set highlight style.
pre.shaku .line.highlight {background-color: var(--color-shaku-highlight-light,color-mix(in srgb, rgb(5, 118, 149) 15%, #fff));display: block;}
pre.shaku .line.highlight {background-color: var(--color-shaku-highlight-light,color-mix(in srgb, rgb(5, 118, 149) 15%, #fff));display: block;}
function useSomeEffect({blog}) {useEffect(() => {return () => {location.href = 'https://jser.dev'}}, [blog])}
function useSomeEffect({blog}) {useEffect(() => {return () => {location.href = 'https://jser.dev'}}, [blog])}
(
and )
are used to mark the selection of next line. optional id inside could be used to set different color.
// ( )function useSomeEffect({blog}) {//( 2 )useEffect(() => {return () => {//( 3 ) ( 3 )location.href = 'https://jser.dev'}}, [blog])}
// ( )function useSomeEffect({blog}) {//( 2 )useEffect(() => {return () => {//( 3 ) ( 3 )location.href = 'https://jser.dev'}}, [blog])}
.shaku-inline-highlight
is used to style the inline blocks, target specific blocks with the id you set - [data-id=*]
.
.shaku-inline-highlight {background-color: #05a4fa30;border-bottom: 2px solid rgb(9, 113, 239);margin: 0 1px;border-radius: 3px;padding: 0 3px;}.shaku-inline-highlight[data-id="1"] {background-color: #05a4fa30;border-bottom: 2px solid rgb(9, 113, 239);}.shaku-inline-highlight[data-id="2"] {background-color: #fa05f230;border-bottom: 2px solid rgb(235, 4, 158);}.shaku-inline-highlight[data-id="3"] {background-color: #05faa930;border-bottom: 2px solid green;}
.shaku-inline-highlight {background-color: #05a4fa30;border-bottom: 2px solid rgb(9, 113, 239);margin: 0 1px;border-radius: 3px;padding: 0 3px;}.shaku-inline-highlight[data-id="1"] {background-color: #05a4fa30;border-bottom: 2px solid rgb(9, 113, 239);}.shaku-inline-highlight[data-id="2"] {background-color: #fa05f230;border-bottom: 2px solid rgb(235, 4, 158);}.shaku-inline-highlight[data-id="3"] {background-color: #05faa930;border-bottom: 2px solid green;}
function useSomeEffect({blog}) {useEffect(() => {// do some stuffreturn () => {location.href = 'https://jser.dev'}}, [blog])}
function useSomeEffect({blog}) {useEffect(() => {// do some stuffreturn () => {location.href = 'https://jser.dev'}}, [blog])}
Similar to highlighting, use @dim
to dim next line, @dim start
and@dim end
for multiple lines.
function useSomeEffect({blog}) {// @dimuseEffect(() => {// do some stuffreturn () => {// @dim startlocation.href = 'https://jser.dev'// @dim end}}, [blog])}
function useSomeEffect({blog}) {// @dimuseEffect(() => {// do some stuffreturn () => {// @dim startlocation.href = 'https://jser.dev'// @dim end}}, [blog])}
Use .dim
to style dimmed lines.
.shaku .line.dim {opacity: 0.3;}
.shaku .line.dim {opacity: 0.3;}
function useSomeEffect({blog}) {useEffect(() => {// do some stuffreturn () => {location.href = 'https://jser.dev'}}, [blog])}
function useSomeEffect({blog}) {useEffect(() => {// do some stuffreturn () => {location.href = 'https://jser.dev'}}, [blog])}
Focus means to highlight some lines and dim the others, it is a shorthand of @highlight
and @dim
. Use @focus
to focus next line, @focus start
and@focus end
for multiple lines.
function useSomeEffect({blog}) {// @focususeEffect(() => {// do some stuffreturn () => {// @focus startlocation.href = 'https://jser.dev'// @focus end}}, [blog])}
function useSomeEffect({blog}) {// @focususeEffect(() => {// do some stuffreturn () => {// @focus startlocation.href = 'https://jser.dev'// @focus end}}, [blog])}
Since it is a shorthand syntax, there is no special class for it.
function component() {This is very beginning
return <Buttonclass="button"--------------Hello World!
disabled/>}
function component() {This is very beginning
return <Buttonclass="button"--------------Hello World!
disabled/>}
Sometimes it is hard to position it right, you can use position shift <
to move shaku elements toward left
function component() {//^<<//[This is very beginning ] <<return <Buttonclass="button"//--------------<<//[Hello World!]<<<disabled/>}
function component() {//^<<//[This is very beginning ] <<return <Buttonclass="button"//--------------<<//[Hello World!]<<<disabled/>}
!
For cases where rendering raw comments are desirable, we can put `!` at the end of shaku lines to escape.
const Hello = "World!"// ^// [Hello World!]Above two lines are not rendered into UI elements!
Since they have
!
at the end and!
is removed when rendered
const Hello = "World!"// ^// [Hello World!]Above two lines are not rendered into UI elements!
Since they have
!
at the end and!
is removed when rendered
Got an issue or have better ideas? Raise an issue on shaku repo.