Hugo 上で何かのリンクを貼ると↓のようになります。

https://github.com/a2-ito/cf-db-test

これだと殺風景なので、Zenn などで自動作成されるブログカードのように装飾してみます。

実際に作ったものがこちら↓

基本的に AI に作ってもらったのですが、いくつか微調整しました。

  • OGP 画像は 160x120 の領域に拡大して収めています。(比率が違う画像の場合、引き伸ばされた感で微妙です、、、)
  • GitHub リポジトリの場合、ogp:title にリポジトリ名と説明が含まれるようで、リポジトリ名だけを title として抽出・表示しています。
  • description が長い場合、カードが縦に伸びてしまうので、2行を超えないよう3行目以降は … と表示されるようにしています。

使い方としては、以下の2ファイルをコピペで配置してもらえればOKです。

  • assets/css/linkcard.css
  • layouts/_shortcodes/linkcard.html

a.link-card {
  box-shadow: none !important;
}

.link-card {
  display: flex;
  gap: 8px;
  border-radius: 12px;
  background: #0b2a4a;
  color: #fff;
  text-decoration: none;
  margin: 1.5em 0;
}

.link-card:hover {
  opacity: 0.9;
}

.link-card__body {
  flex: 1;
  min-width: 0;
  padding: 12px;
}

.link-card__title {
  font-weight: 700;
  font-size: 1.05rem;
  margin-bottom: 4px;
}

.link-card__desc {
  font-size: 0.9rem;
  opacity: 0.85;
  margin-bottom: 6px;
  line-height: 1.4;

  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.link-card__site {
  font-size: 0.75rem;
  opacity: 0.6;
}

.link-card__image {
  width: 160px;
  height: 120px;
  overflow: hidden;
  flex-shrink: 0;

  background: #0a1e33; /* 余白用 */
  display: flex;
  align-items: center;
  justify-content: center;
}

.link-card__image img {
  width: 100%;
  height: 100%;
  display: block;
  border-radius: 0px 8px 8px 0px;
}

layouts/_shortcodes/linkcard.html

{{- $url := .Get 0 -}}

{{- $res := resources.GetRemote $url -}}
{{- if not $res -}}
  <a href="{{ $url }}" target="_blank" rel="noopener">{{ $url }}</a>
{{- else -}}

{{- $html := $res.Content | safeHTML -}}

{{- $title := "" -}}
{{- $desc := "" -}}
{{- $image := "" -}}
{{- $site := "" -}}

{{- with (replaceRE `(?s).*<meta[^>]+property=["']og:title["'][^>]+content=["']([^"']+)["'][^>]*>.*` `$1` $html) -}}
  {{- if ne . $html }}{{ $title = . }}{{ end -}}
{{- end -}}

{{- with (replaceRE `(?s).*<meta[^>]+property=["']og:description["'][^>]+content=["']([^"']+)["'][^>]*>.*` `$1` $html) -}}
  {{- if ne . $html }}{{ $desc = . }}{{ end -}}
{{- end -}}

{{- with (replaceRE `(?s).*<meta[^>]+property=["']og:image["'][^>]+content=["']([^"']+)["'][^>]*>.*` `$1` $html) -}}
  {{- if ne . $html }}{{ $image = . }}{{ end -}}
{{- end -}}

{{- with (replaceRE `(?s).*<meta[^>]+property=["']og:site_name["'][^>]+content=["']([^"']+)["'][^>]*>.*` `$1` $html) -}}
  {{- if ne . $html }}{{ $site = . }}{{ end -}}
{{- end -}}

{{- if in $url "github.com" -}}
  {{- $title = replaceRE `^GitHub - ([^:]+):.*$` `$1` $title -}}
{{- end -}}

<a
  href="{{ $url }}"
  target="_blank"
  rel="noopener"
  class="link-card"
>
  <div class="link-card__body">
    <div class="link-card__title">
      {{ if $title }}{{ $title }}{{ else }}{{ $url }}{{ end }}
    </div>

    {{ if $desc }}
      <div class="link-card__desc">{{ $desc }}</div>
    {{ end }}

    {{ if $site }}
      <div class="link-card__site">{{ $site }}</div>
    {{ end }}
  </div>

  {{ if $image }}
    <div class="link-card__image">
      <img src="{{ $image }}" alt="" loading="lazy" />
    </div>
  {{ end }}
</a>

{{- end -}}