Từ ngày 01/01/2019, 12bit.vn đã chuyển qua blog riêng, xây dựng bằng Hugo thay vì sử dụng Medium như trước. Vì vậy chúng mình cũng có cơ hội để tìm hiểu nhiều về Hugo hơn. Chúng mình từng thử custom lại code của Hugo để hỗ trợ hiển thị danh sách contributor của một bài post hoặc lấy commit author để làm author cho bài viết, nhưng nếu dùng cách đó thì các bạn cũng phải sử dụng bản Hugo của tụi mình để build, mà như vậy thì không tiện, cuối cùng chúng mình chọn shortcode, tiện hơn và dễ hơn.
Trong bài viết này mình sẽ giới thiệu cho các bạn những shortcode mà tụi mình đang sử dụng cho 12bit.vn:
Embed Codepen
Blog về frontend thì không khỏi phải embed demo nào đó, Codepen là một công cụ rất hữu ích. Cú pháp shortcode có thể như sau:
{{<codepen username pen_id height_in_px>}}
Nếu không set giá trị height
thì height
mặc định sẽ là 500px. Ví dụ:
{{<codepen tatthien LgMKpm 400>}}
Mã nguồn
shortcodes/codepen.html
{{ $height := 500 }}
{{ if isset .Params 2 }}
{{ $height = .Get 2 }}
{{ end }}
<p>
<iframe
height='{{ $height }}'
scrolling='no'
src='//codepen.io/{{ index .Params 0 }}/embed/{{ index .Params 1 }}/?height=265&theme-id=dark&default-tab=result'
frameborder='no'
allowtransparency='true'
allowfullscreen='true'
style='width: 100%;'
>
</iframe>
</p>
runkit
Runkit cho phép bạn embed một đoạn code Nodejs vào website và run nó trực tiếp. Cái hay của Runkit là nó không giống như gist, bạn không cần phải truy cập vào website cua Runkit để tạo một file sau đó mới embed, mà chỉ cần load script của họ, sau đó nó sẽ tự động lấy nội dung trên site của bạn và embed thành một iframe có thể run được, trong trường hợp Runkit không hoạt động, thì người đọc vẫn có thể xem code được.
Chúng ta sẽ có cấu trúc như sau:
{{% runkit unique-id %}}
your code block with ``` code and {{% /runkit %}}
unique-id
ở đây chỉ là một id bất kỳ nào đó nhằm phân biệt giữa các đoạn code với nhau. Theo document của Runkit thì nó cần id này để sau khi script load xong sẽ dùng id này để lấy code và tạo embed.
Mã nguồn
shortcodes/runkit.html
<div class="runkit" id="{{ .Get 0 }}">{{ .Inner }}</div>
<script src="https://embed.runkit.com" data-element-id="{{ .Get 0 }}"></script>
Can I use
Có nhiều bài viết trên 12bit giới thiệu về các API mới mà không phải mọi browser đều hỗ trợ, sẽ thật tiện nếu các bạn có thể biết được API đó đã hỗ trợ trên những browser nào rồi. caniuse là website cho các bạn biết điều đó, nên sẽ tiện lắm nếu có thể embed vào trực tiếp trên website.
Bạn @IreAderinokun đã xây dựng thư viện Can I Use Embed để hỗ trợ việc này, những gì chúng ta cần bây giờ chỉ là load script của thư viện này thôi, nhưng sẽ chia ra làm hai phần.
Chúng ta cần làm hai việc:
- Render div kèm theo attribute chứa tên các feature cần check.
- Load thư viện ở footer
Mã nguồn
shortcodes/caniuse.html
{{ .Page.Scratch.Set "include_caniuse" true }}
{{ $periods := .Get "periods" | default "future_1,current,past_1,past_2" }}
{{ $features := default (.Get "features") (.Get 0) }}
<div class="ciu_embed" data-feature="{{ $features }}" data-periods="{{ $periods }}">
<a href="http://caniuse.com/#feat={{ $features }}">Can I Use {{ $features }}?</a>
</div>
Chúng ta lưu giá trị include_caniuse
vào Scratch, và check giá trị này ở footer để chỉ load script khi cần thiết:
footer.html
{{ if ($.Page.Scratch.Get "include_caniuse") "true" }}
<script async src="https://cdn.jsdelivr.net/gh/ireade/caniuse-embed/caniuse-embed.min.js"></script>
{{ end }}
Cách dùng
{{< caniuse features="proxy" >}}
image-zoom
Không phải hiếm gặp các trường hợp phải đăng ảnh chụp một form hoặc ảnh gif với những chi tiết nhỏ. Nên nhu cầu zoom ảnh cũng thường gặp, Medium có chức năng rất hay là khi bạn click vào ảnh thì ảnh sẽ zoom lên full-screen. Mình thích chức năng này và đã tạo một shortcode cho nó:
{{< zoom-img src="/img/articles/default-thumb-1200-630.png" >}}
Mã nguồn
shortcodes/zoom-img.html
{{ .Page.Scratch.Set "include_image_zoom" true }}
{{- $title := .Get "url" | default "" -}}
{{- $src := .Get "src" | default "" -}}
<p>
<img
data-zoomable
src="{{ $src }}"
data-zoom-src="{{ $src }}"
title="{{ $title }}"
alt="{{ $title }}"
>
</p>
Tương tự như shortcode caniuse, chúng ta cũng set giá trị cho include_image_zoom
để có thể load script ở dưới footer, vì chúng ta không muốn load script ngay tại đây đúng không.
footer.html
{{ if ($.Page.Scratch.Get "include_image_zoom") "true" }}
<script src="https://unpkg.com/medium-zoom@1.0.2/dist/medium-zoom.min.js" async defer onload="mediumZoom('[data-zoomable]');"></script>
{{ end }}
mermaid
Mình cũng thường gặp các trường hợp phải dùng diagram, như khi mô tả data flow, sequence diagram, thuật toán, … Và viết bài trong hugo thì cần sử dụng markdown, sẽ tiện lợi nếu có thể vẽ diagram bằng chính markdown và thư viện mermaidjs chính là thứ làm được điều đó.
Cách dùng
{{< mermaid >}}
graph TB
c1-->a2
subgraph one
a1-->a2
end
subgraph two
b1-->b2
end
subgraph three
c1-->c2
end
{{< /mermaid >}}
Mã nguồn
shortcodes/mermaid.html
{{ .Page.Scratch.Set "include_mermaid" true }}
<div class="mermaid">
{{ .Inner }}
</div>
tương tự như các shortcode cần load thêm script, chúng ta cũng set giá trị cho include_mermaid
và check trong footer.html
{{ if ($.Page.Scratch.Get "include_mermaid") "true" }}
<script async src="https://unpkg.com/mermaid@8.0.0/dist/mermaid.min.js"></script>
{{ end }}
oembed thần thánh
Và cuối cùng, khi bạn cảm thấy mệt mỏi và “ngốc ngếch” vì phải support đủ loại website mà vốn chính website đó đã có hỗ trợ oembed. Thì hãy implement một shortcode hỗ trợ oembed. Oembedly là dịch vụ chuyên về oembed, họ có API và thư viện JavaScript để giúp chúng ta embed bất kỳ website nào mà họ có hỗ trợ. Medium sử dụng dịch vụ của họ để làm tính năng oembed.
Cú pháp sẽ giống như sau:
{{< oembed url="https://open.spotify.com/playlist/37i9dQZEVXbc3uyDjJcA7l" title="ahhi" >}}
Kết quả:
Mã nguồn
shortcodes/oembed.html
{{ .Page.Scratch.Set "include_embedly" true }}
{{- $url := .Get "url" -}}
{{- $title := .Get "url" | default "" -}}
<div class="oembed-card">
<a data-card-controls="0" class="embedly-card" href="{{ $url }}">{{ $title }}</a>
</div>
footer.html
{{ if ($.Page.Scratch.Get "include_embedly") "true" }}
<style class="embedly-css">
.pair-bd .art-bd{
padding: 0;
}
.card .hdr {
display:none;
}
.card .brd {
display:none;
}
</style>
<script src="//cdn.embedly.com/widgets/platform.js" async defer></script>
{{ end }}
Oembedly hỗ trợ chúng ta custom style của card bằng cách thêm style có class embedly-css
. Nên mình dùng nó để ẩn header và footer của card đi.
Kết
Còn nhiều shortcode khác trong repos của 12bit.vn mà bạn có thể xem tại đây: github .
Các bạn có thể xem thêm các shortcode khác tại trang shortcode