🔄

index.htmlだけでMicrosoft TeamsのAdaptive Cards

2024/11/17に公開

Microsoft TeamsのワークフローでおなじみAdaptive Cards(アダプティブカード)を書く必要性が出たので、CDNのjsDelivrを使い、index.htmlだけで書けるようにしたいと思います。

https://adaptivecards.io/

https://www.npmjs.com/package/adaptivecards

まずindex.htmlを作成し、npmの例をコピペして動かしてみます。

index.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width" />
    <title>Adaptive Cards</title>
    <meta name="description" content="Zenn" />
  </head>
  <body>
    <script src="https://cdn.jsdelivr.net/npm/adaptivecards/dist/adaptivecards.min.js"></script>
    <script>
var card = {
    "type": "AdaptiveCard",
    "version": "1.0",
    "body": [
        {
            "type": "Image",
            "url": "http://adaptivecards.io/content/adaptive-card-50.png"
        },
        {
            "type": "TextBlock",
            "text": "Hello **Adaptive Cards!**"
        }
    ],
    "actions": [
        {
            "type": "Action.OpenUrl",
            "title": "Learn more",
            "url": "http://adaptivecards.io"
        },
        {
            "type": "Action.OpenUrl",
            "title": "GitHub",
            "url": "http://github.com/Microsoft/AdaptiveCards"
        }
    ]
};

var adaptiveCard = new AdaptiveCards.AdaptiveCard();

adaptiveCard.hostConfig = new AdaptiveCards.HostConfig({
    fontFamily: "Segoe UI, Helvetica Neue, sans-serif"
});

adaptiveCard.onExecuteAction = function(action) { alert("Ow!"); }

adaptiveCard.parse(card);

var renderedCard = adaptiveCard.render();

document.body.appendChild(renderedCard);
    </script>
  </body>
</html>

v1

MarkdownがHTMLでレンダリングされないのはいいとして、スタイルが全く適用されていません。
npmのバージョン情報を確認してみると、latestはv1参照しているので、新しいバージョンにすることでjsDelivrからデフォルトのCSSを取得できるようになり、スタイルを適用することができるようです。

+    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/adaptivecards@3.0.4/dist/adaptivecards.css" />
-    <script src="https://cdn.jsdelivr.net/npm/adaptivecards/dist/adaptivecards.min.js"></script>
+    <script src="https://cdn.jsdelivr.net/npm/adaptivecards@3.0.4/dist/adaptivecards.min.js"></script>

https://github.com/microsoft/AdaptiveCards/blob/main/source/nodejs/adaptivecards/docs/README.md

例もvarを使っていたり、スキーマがなかったり、バージョンが古かったり、ボタンを押してもOw!と表示されるだけでURLを開くアクションをしてくれなかったり、JSONではなく連想配列の変数をそのまま使っていたり、色々古い情報が放置されたままになっているので、ドキュメントを見ながらちゃんとしたコードに修正して動かしてみます。

index.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width" />
    <title>Adaptive Cards</title>
    <meta name="description" content="Zenn" />
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/adaptivecards@3.0.4/dist/adaptivecards.css" />
    <script id="content" type="application/json">
{
  "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
  "type": "AdaptiveCard",
  "version": "1.5",
  "body": [
    {
      "type": "Image",
      "url": "http://adaptivecards.io/content/adaptive-card-50.png"
    },
    {
      "type": "TextBlock",
      "text": "Hello **Adaptive Cards!**"
    }
  ],
  "actions": [
    {
      "type": "Action.OpenUrl",
      "title": "Learn more",
      "url": "http://adaptivecards.io"
    },
    {
      "type": "Action.OpenUrl",
      "title": "GitHub",
      "url": "http://github.com/Microsoft/AdaptiveCards"
    }
  ]
}
    </script>
  </head>
  <body>
    <div id="container" style="max-width: 320px">
    </div>
    <script src="https://cdn.jsdelivr.net/npm/adaptivecards@3.0.4/dist/adaptivecards.min.js"></script>
    <script>
const card = new AdaptiveCards.AdaptiveCard();
card.hostConfig = new AdaptiveCards.HostConfig({
  fontFamily: "Segoe UI, Helvetica Neue, sans-serif",
});
card.onExecuteAction = function(action) {
  window.open(action.url, "_blank");
};
card.parse(JSON.parse(document.getElementById("content").textContent));

document.getElementById("container").appendChild(card.render());
    </script>
  </body>
</html>

v3

新しいバージョンで配布されているデフォルトのCSSを適用することで、おおむね期待通りのAdaptive Cardsを表示することができました。

https://www.npmjs.com/package/markdown-it

ではMarkdownがHTMLでレンダリングされていないので、README.mdで紹介されているようにMarkdown itを追加したいと思います。

     <script src="https://cdn.jsdelivr.net/npm/adaptivecards@3.0.4/dist/adaptivecards.min.js"></script>
+    <script src="https://cdn.jsdelivr.net/npm/markdown-it@14.1.0/dist/markdown-it.min.js"></script>
     <script>

md

期待通りのAdaptive Cardsを表示することができました。

ただ私はMicrosoft TeamsのAdaptive Cardsを書きたいので、Microsoft Teamsと同じスタイルを適用したいところです。
Adaptive CardsのDesignerではMicrosoft Teamsと同じスタイルで表示できているし、実現できそうなので。

https://adaptivecards.io/designer/

https://www.npmjs.com/package/adaptivecards-designer

もしかしてnpmでCSSを配布しているのではないかと思い、ソースコードを確認したところ、ありました。

https://github.com/microsoft/AdaptiveCards/blob/main/source/nodejs/adaptivecards-designer/src/containers/teams/teams-container-light.css

ダークモード用のCSSも配布しているみたいですが、文字の色を自動的に反転してくれないみたいなので、ライトモードで妥協します。

-    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/adaptivecards@3.0.4/dist/adaptivecards.css" />
+    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/adaptivecards-designer@2.4.4/dist/containers/teams-container-light.css" />

まずはCSSをadaptivecardsパッケージで配布しているデフォルトのものではなく、adaptivecards-designerパッケージで配布しているMicrosoft Teamsのものに変更します。

-document.getElementById("container").appendChild(card.render());
+const outerFrame = document.createElement("div");
+outerFrame.classList.add("teams-frame");
+const innerFrame = document.createElement("div");
+innerFrame.classList.add("teams-inner-frame");
+const teams = document.createElement("div");
+teams.classList.add("teams-card");
+
+teams.appendChild(card.render());
+innerFrame.appendChild(teams);
+outerFrame.appendChild(innerFrame);
+document.getElementById("container").appendChild(outerFrame);

Microsoft TeamsのCSSはデフォルトのCSSと異なり、別途適用する必要のあるスタイルがあるため、クラスを追加したdiv要素を作ってあげます。

完成したものがこちら。

index.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width" />
    <title>Adaptive Cards</title>
    <meta name="description" content="Zenn" />
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/adaptivecards-designer@2.4.4/dist/containers/teams-container-light.css" />
    <script id="content" type="application/json">
{
  "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
  "type": "AdaptiveCard",
  "version": "1.5",
  "body": [
    {
      "type": "Image",
      "url": "http://adaptivecards.io/content/adaptive-card-50.png"
    },
    {
      "type": "TextBlock",
      "text": "Hello **Adaptive Cards!**"
    }
  ],
  "actions": [
    {
      "type": "Action.OpenUrl",
      "title": "Learn more",
      "url": "http://adaptivecards.io"
    },
    {
      "type": "Action.OpenUrl",
      "title": "GitHub",
      "url": "http://github.com/Microsoft/AdaptiveCards"
    }
  ]
}
    </script>
  </head>
  <body>
    <div id="container" style="max-width: 320px">
    </div>
    <script src="https://cdn.jsdelivr.net/npm/adaptivecards@3.0.4/dist/adaptivecards.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/markdown-it@14.1.0/dist/markdown-it.min.js"></script>
    <script>
const card = new AdaptiveCards.AdaptiveCard();
card.hostConfig = new AdaptiveCards.HostConfig({
  fontFamily: "Segoe UI, Helvetica Neue, sans-serif",
});
card.onExecuteAction = function(action) {
  window.open(action.url, "_blank");
};
card.parse(JSON.parse(document.getElementById("content").textContent));

const outerFrame = document.createElement("div");
outerFrame.classList.add("teams-frame");
const innerFrame = document.createElement("div");
innerFrame.classList.add("teams-inner-frame");
const teams = document.createElement("div");
teams.classList.add("teams-card");

teams.appendChild(card.render());
innerFrame.appendChild(teams);
outerFrame.appendChild(innerFrame);
document.getElementById("container").appendChild(outerFrame);
    </script>
  </body>
</html>

teams

index.htmlだけでMicrosoft TeamsのAdaptive Cardsを表示することができました。

ちなみに以下のように変更するとOutlook Actionable Messagesの表示にもできます。

-    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/adaptivecards@3.0.4/dist/adaptivecards.css" />
+    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/adaptivecards-designer@2.4.4/dist/containers/outlook-container.css" />
-document.getElementById("container").appendChild(card.render());
+const outlook = document.createElement("div");
+outlook.classList.add("outlook-frame");
+
+outlook.appendChild(card.render());
+document.getElementById("container").appendChild(outlook);

outlook

Discussion