Skip to content

Commit a8266d9

Browse files
committed
Support fretboard
1 parent afd2ab0 commit a8266d9

File tree

6 files changed

+832
-68
lines changed

6 files changed

+832
-68
lines changed

example/index.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,12 +374,25 @@ stop
374374
}
375375
```
376376

377+
### Fretboard
378+
379+
```fretboard {title="horizontal, 6 frets, with nut", type="h6"}
380+
-oO-*-
381+
--o-o-
382+
-o-oo-
383+
-o-oO-
384+
-oo-o-
385+
-*O-o-
386+
3
387+
```
388+
377389
> More information about **sequence diagrams** syntax [here](http://bramp.github.io/js-sequence-diagrams/).
378390
> More information about **flow charts** syntax [here](http://adrai.github.io/flowchart.js/).
379391
> More information about **graphviz** syntax [here](http://www.tonyballantyne.com/graphs.html)
380392
> More information about **mermaid** syntax [here](http://mermaid-js.github.io/mermaid)
381393
> More information about **abc** syntax [here](http://abcnotation.com/learn)
382394
> More information about **vega** syntax [here](https://vega.github.io/vega-lite/docs)
395+
> More information about **fretboard** syntax [here](https://hackmd.io/@docs/fretboard-syntax)
383396
384397
## YAML metadata
385398

layout.html

Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,194 @@
412412
.hljs-ln-code {
413413
padding: 0px 0px 0px 16px !important;
414414
}
415+
416+
/*---fretboard---*/
417+
.fretTitle {
418+
color: #555;
419+
text-align: center;
420+
font-family: "Helvetica Neue", sans-serif;
421+
line-height: 1.4;
422+
font-size: 1.6em;
423+
margin: 10px 0 10px 0;
424+
font-weight: 900;
425+
padding: 5px;
426+
}
427+
428+
.fretContainer section {
429+
padding: 20px;
430+
}
431+
432+
.fretContainer .content {
433+
max-width: 960px;
434+
margin: auto;
435+
}
436+
437+
.fretContainer,
438+
.fretContainer_h {
439+
outline: solid 1px #eeee;
440+
margin: 0 auto;
441+
padding: 15px 0;
442+
}
443+
444+
.fretContainer {
445+
width: 320px;
446+
}
447+
448+
.fretContainer_h {
449+
max-width: 400px;
450+
}
451+
452+
.svg_wrapper {
453+
background-color: #fff;
454+
position: relative;
455+
height: 0;
456+
}
457+
458+
.svg_wrapper svg.fretboard_bg {
459+
position: absolute;
460+
top: 0;
461+
left: 0;
462+
z-index: 0;
463+
}
464+
465+
.svg_wrapper .cells {
466+
width: 100%;
467+
height: 100%;
468+
position: absolute;
469+
top: 0;
470+
left: 0;
471+
}
472+
473+
.svg_wrapper.v4 {
474+
padding-top: 91.6666666667%;
475+
}
476+
477+
.svg_wrapper.v5 {
478+
padding-top: 106.9444444444%;
479+
}
480+
481+
.svg_wrapper.v7 {
482+
padding-top: 137.5%;
483+
}
484+
485+
.svg_wrapper.v9 {
486+
padding-top: 168.0555555556%;
487+
}
488+
489+
.svg_wrapper.v12 {
490+
padding-top: 213.8888888889%;
491+
}
492+
493+
.svg_wrapper.v15 {
494+
padding-top: 259.7222222222%;
495+
}
496+
497+
.svg_wrapper.v .cell svg {
498+
width: 12.5%;
499+
float: left;
500+
display: block;
501+
}
502+
503+
.svg_wrapper.v4 .cell svg {
504+
height: 16.6666666667%;
505+
}
506+
507+
.svg_wrapper.v5 .cell svg {
508+
height: 14.2857142857%;
509+
}
510+
511+
.svg_wrapper.v7 .cell svg {
512+
height: 11.1111111111%;
513+
}
514+
515+
.svg_wrapper.v9 .cell svg {
516+
height: 9.0909090909%;
517+
}
518+
519+
.svg_wrapper.v12 .cell svg {
520+
height: 7.1428571429%;
521+
}
522+
523+
.svg_wrapper.v15 .cell svg {
524+
height: 5.8823529412%;
525+
}
526+
527+
.svg_wrapper.h5 {
528+
padding-top: 85.7142857143%;
529+
}
530+
531+
.svg_wrapper.h6 {
532+
padding-top: 75%;
533+
}
534+
535+
.svg_wrapper.h7 {
536+
padding-top: 72.7272727273%;
537+
}
538+
539+
.svg_wrapper.h .cell svg {
540+
height: 12.5%;
541+
float: left;
542+
display: block;
543+
z-index: 2;
544+
}
545+
546+
.svg_wrapper.h5 .cell svg {
547+
width: 14.2857142857%;
548+
}
549+
550+
.svg_wrapper.h6 .cell svg {
551+
width: 12.5%;
552+
}
553+
554+
.svg_wrapper.h7 .cell svg {
555+
width: 12.1212121212%;
556+
}
557+
558+
/* Fretboard Element Styles */
559+
560+
.cell.dot .fretb_dot {
561+
fill: #27a9e1;
562+
}
563+
564+
.cell.dot.root .fretb_dot {
565+
fill: #f05a28;
566+
}
567+
568+
.cell.dot.faded .fretb_dot {
569+
opacity: .25;
570+
}
571+
572+
.fretboard_bg .fret_bg rect {
573+
fill: #fff;
574+
}
575+
576+
.fretboard_bg .frets rect {
577+
fill: #ddd;
578+
}
579+
580+
.fretboard_bg .nut rect {
581+
fill: #6e6e6e;
582+
}
583+
584+
.fretboard_bg .strings rect {
585+
fill: #6e6e6e;
586+
}
587+
588+
.svg_wrapper.noNut .fretboard_bg .nut rect {
589+
fill: none;
590+
}
591+
592+
@media all and (max-width: 400px) {
593+
.fretContainer_h {
594+
max-width: 288px;
595+
}
596+
}
597+
598+
@media all and (max-width: 420px) {
599+
.fretContainer {
600+
max-width: 220px;
601+
}
602+
}
415603
</style>
416604
</head>
417605

lib/converter.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -154,8 +154,6 @@ export class Convert {
154154
* @param destDir the path of destination directory e.g. ["./build"]
155155
*/
156156
public convertFiles(filePathsOrDir: fs.PathLike[], destDir: fs.PathLike) {
157-
console.log(filePathsOrDir)
158-
159157
if (!fs.existsSync(destDir)) {
160158
fs.mkdirSync(destDir)
161159
}

lib/fenceX.ts

Lines changed: 22 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import MarkdownIt from 'markdown-it/lib'
22
import Token from 'markdown-it/lib/token'
3+
import { PlantUML } from './plantUML'
4+
import { renderFretBoard } from './fretboard'
35
const Papa = require('papaparse')
4-
const deflate = require('deflate-js')
56

67
// eslint-disable-next-line @typescript-eslint/no-unused-vars
78
export function MarkdownItFenceX(md: MarkdownIt, _options: MarkdownIt.Options) {
@@ -31,7 +32,12 @@ export function MarkdownItFenceX(md: MarkdownIt, _options: MarkdownIt.Options) {
3132
// 5. special case (Not always support in our package)
3233
// input {delimiter = = = = = header = true}
3334
// output {delimiter: "=", header: true}
34-
function parseUserDefinedCSVTableConfig(config: string): Map<string, any> {
35+
36+
// For fretboard
37+
// input {title="horizontal, 6 frets", type="h6"}
38+
// ^ comma between value and next key
39+
// output {title: "horizontal, 6 frets", type: "h6"}
40+
function parseUserDefinedConfig(config: string): Map<string, any> {
3541
const map = new Map()
3642

3743
config = config.trim()
@@ -54,9 +60,9 @@ export function MarkdownItFenceX(md: MarkdownIt, _options: MarkdownIt.Options) {
5460
for (let i = 0; i < config.length; i++) {
5561
if (state === parseKey) {
5662
if (config[i] === '=') {
57-
const key = config.substring(j, i).trim()
63+
const key = config.substring(j, i).replace(',', '').trim()
5864
if (key !== '') {
59-
keyList.push(config.substring(j, i).trim())
65+
keyList.push(key)
6066
state = prepareParseValue
6167
}
6268
j = i + 1
@@ -111,14 +117,14 @@ export function MarkdownItFenceX(md: MarkdownIt, _options: MarkdownIt.Options) {
111117
for (let i = 0; i < state.tokens.length; i++) {
112118
const token: Token = state.tokens[i]
113119
if (token.type === 'fence') {
114-
const params: string[] = token.info.split(" ")
120+
const params: string[] = token.info.split(' ')
115121
if (params[0] === 'csvpreview') {
116-
const config = parseUserDefinedCSVTableConfig(params.slice(1).join(" "))
122+
const config = parseUserDefinedConfig(params.slice(1).join(' '))
117123
const res = Papa.parse(token.content.trim(), Object.fromEntries(config))
118124
const newTokens: Token[] = []
119125
newTokens.push(new Token('csvtable_open', 'table', 1))
120126
if (config.has('header') && (config.get('header') as boolean)) {
121-
// render header of table
127+
// render the header of table
122128
if (res.data.length == 0) continue;
123129

124130
const keys = Object.keys(res.data[0]);
@@ -172,69 +178,19 @@ export function MarkdownItFenceX(md: MarkdownIt, _options: MarkdownIt.Options) {
172178
['data-url', url]]
173179
newTokens.push(img)
174180
state.tokens = md.utils.arrayReplaceAt(state.tokens, i, newTokens)
181+
} else if (params[0] === 'fretboard') {
182+
const config = parseUserDefinedConfig(params.slice(1).join(' '))
183+
let title = config.get('title') as string
184+
let type = config.get('type') as string
185+
let rendered = renderFretBoard(token.content, { title: title, type: type })
186+
const fret = new Token('html_block', 'div', 0)
187+
fret.content = rendered
188+
189+
state.tokens = md.utils.arrayReplaceAt(state.tokens, i, [fret])
175190
}
176191
}
177192
}
178193
}
179194

180195
md.core.ruler.push('codeX', codeX)
181-
}
182-
183-
class PlantUML {
184-
private encode6bit(b: number): string {
185-
if (b < 10) {
186-
return String.fromCharCode(48 + b);
187-
}
188-
b -= 10;
189-
if (b < 26) {
190-
return String.fromCharCode(65 + b);
191-
}
192-
b -= 26;
193-
if (b < 26) {
194-
return String.fromCharCode(97 + b);
195-
}
196-
b -= 26;
197-
if (b == 0) {
198-
return '-';
199-
}
200-
if (b == 1) {
201-
return '_';
202-
}
203-
return '?';
204-
}
205-
206-
private append3bytes(b1: number, b2: number, b3: number) {
207-
const c1 = b1 >> 2;
208-
const c2 = ((b1 & 0x3) << 4) | (b2 >> 4);
209-
const c3 = ((b2 & 0xF) << 2) | (b3 >> 6);
210-
const c4 = b3 & 0x3F;
211-
let r = "";
212-
r += this.encode6bit(c1 & 0x3F);
213-
r += this.encode6bit(c2 & 0x3F);
214-
r += this.encode6bit(c3 & 0x3F);
215-
r += this.encode6bit(c4 & 0x3F);
216-
return r;
217-
}
218-
219-
private encode64(data: string) {
220-
let r = '';
221-
for (let i = 0; i < data.length; i += 3) {
222-
if (i + 2 == data.length) {
223-
r += this.append3bytes(data.charCodeAt(i), data.charCodeAt(i + 1), 0);
224-
} else if (i + 1 == data.length) {
225-
r += this.append3bytes(data.charCodeAt(i), 0, 0);
226-
} else {
227-
r += this.append3bytes(data.charCodeAt(i), data.charCodeAt(i + 1),
228-
data.charCodeAt(i + 2));
229-
}
230-
}
231-
return r;
232-
}
233-
234-
public generateURL(value: string) {
235-
const encoded = new TextEncoder().encode(value);
236-
const compressedCharArray = deflate.deflate(encoded, 9);
237-
const compressed = String.fromCharCode.apply(null, compressedCharArray)
238-
return this.encode64(compressed);
239-
}
240196
}

0 commit comments

Comments
 (0)