(This is part 2 in a set of failed experiments trying to generate SVG tweets in Hugo. I eventually abandoned this goal, and generate HTML archives of tweets instead.)
You should be able to calculate the size of things via javascript right?
I tried generating <object>
and <iframe>
embeds and calculating the resulting size in JavaScript,
but it doesn’t work.
Setup
Add this to config.yaml:
mediaTypes:
...
text/html+tweet:
suffixes: ["tweet.html"]
outputFormats:
...
HtmlTweet:
mediatype: text/html+tweet
suffix: tweet.html
isPlainText: true
notAlternative: false
Add this to content/archive/tweets/_index.md:
type: tweets
cascade:
type: tweets
outputs:
- HTML
- SVG
- HtmlTweet
Here’s layouts/tweets/single.tweet.html
:
{{- $tweet := index .Site.Data.tweets .Params.tweetid -}}
<html style="height: 100%; overflow: visible;">
<head>
<base target="_parent" />
<title>Tweet from @{{ $tweet.username}} on {{ .Date.Format .Site.Params.dateform }}</title>
<style>
{{/* TODO: split out CSS so that I don't have to include all website CSS */}}
{{- $inlineTweetStandalone := resources.Get "inlineTweetStandalone.scss" | resources.ToCSS | minify -}}
{{- $inlineTweetStandalone.Content | safeCSS -}}
</style>
<script>
/* Display explanation text for an inline tweet
*/
function toggleInlineTweetExplanation(button) {
const expl = button.parentElement.getElementsByClassName('inline-tweet-about-explanation')[0];
console.log(expl.style.display);
if (expl.style.display === 'none'){
expl.style.display = 'block';
} else {
expl.style.display = 'none';
}
}
/* Code to expand/collapse all tweets on a page
*/
function setInlineTweetCollapsibleDisplay(state) {
const tweets = document.getElementsByClassName("inline-tweet-collapsible");
for (const tweet of tweets) {
switch (state) {
case "open": tweet.open = true; break;
case "closed": tweet.open = false; break;
default: console.log(`Unknown state: ${state}`);
}
}
}
/* Notify the parent of this iframe (if any) that the size has changed
*/
// function notifyParentFrameSizeChange() {
// const msg = {
// mrlevent: "resize",
// w: window.innerWidth,
// h: window.innerHeight,
// }
// console.log(window.offsetHeight)
// window.parent.postMessage(msg, "*");
// }
// window.addEventListener('resize', notifyParentFrameSizeChange);
</script>
</head>
<body>
<section id="content" class="single-tweet">
{{ partial "inlineTweet.html" (dict "ctx" . "tweetId" .Params.tweetid) }}
</section>
<script>
const resizeObserver = new ResizeObserver(e => {
const w = window.innerWidth;
const h = window.innerHeight;
const msg = {mrlevent: "resize", w, h}
console.log(`In resizeObserver, ${w}x${h}`)
console.log(window.offsetHeight)
window.parent.postMessage(msg, "*");
});
resizeObserver.observe(document.documentElement);
</script>
</body>
</html>
Here’s layouts/tweets/single.html
that will inline the above:
{{- partial "header.html" . -}}
{{- $formattedDate := .Date.Format .Site.Params.dateform -}}
{{- $tweet := index .Site.Data.tweets .Params.tweetid -}}
<section id="content" class="single-tweet">
<p><a href='{{ ref . "/archive/tweets" }}'>About archived tweets</a></p>
<h1 id="single-tweet-page-h1">Tweet from @{{ $tweet.username}} on {{ .Date.Format .Site.Params.dateform }}</h1>
<!--object id="embedded-tweet-html-object" class="embedded-tweet-html-object" style="width: 100%;" data="index.tweet.html" type="text/html"></object-->
<iframe id="embedded-tweet-html-iframe" class="embedded-tweet-html-iframe" style="width: 100%;" scrolling="no" src="index.tweet.html"></iframe>
</section>
<script>
const tweetHtmlObject = document.getElementById("embedded-tweet-html-object");
</script>
{{ partial "taxonomyList.html" . }}
{{ partial "footer.html" . }}
I tried a bunch of different things. Here’s a version of single.html
that tries various things at the same time.
{{- partial "header.html" . -}}
{{- $formattedDate := .Date.Format .Site.Params.dateform -}}
{{- $tweet := index .Site.Data.tweets .Params.tweetid -}}
<section id="content" class="single-tweet">
<p><a href='{{ ref . "/archive/tweets" }}'>About archived tweets</a></p>
<h1>Experiments</h1>
<h2>An HTML page in an iframe</h2>
<iframe id="embedded-tweet-iframe" scrolling="no" class="" src="index.tweet.html"></iframe>
<h2>An HTML page as an object</h2>
<object id="embedded-tweet-html-object" class="" data="index.tweet.html" type="text/html"></object>
<h2>The SVG as an object</h2>
<object id="embedded-tweet-svg-object" data="index.svg" type="image/svg+xml"></object>
<h2>The SVG as an img</h2>
<img id="embedded-tweet-svg-img" style="" src="index.svg" />
<h1 id="single-tweet-page-h1">Tweet from @{{ $tweet.username}} on {{ .Date.Format .Site.Params.dateform }}</h1>
{{ partial "inlineTweet.html" (dict "ctx" . "tweetId" .Params.tweetid) }}
</section>
<script>
const tweetHtmlIframe = document.getElementById("embedded-tweet-iframe");
const tweetHtmlObject = document.getElementById("embedded-tweet-html-object");
const tweetSvgObject = document.getElementById("embedded-tweet-svg-object");
const tweetSvgImage = document.getElementById("embedded-tweet-svg-img");
</script>
{{ partial "taxonomyList.html" . }}
{{ partial "footer.html" . }}
Here’s assets/inlineTweetStandalone.scss
:
blockquote.inline-tweet {
--body-fg-color-deemphasize-nontext: #ddd;
--body-fg-color-deemphasize-text: gray;
--inline-tweet-dt-fg-color: rgb(101, 119, 134);
--inline-tweet-username-fg-color: rgb(101, 119, 134);
--inline-tweet-about-bg-color: rgb(75, 75, 172);
--inline-tweet-about-fg-color: white;
*, *:hover, *:hover *{
all: revert;
}
.inline-tweet-qt {
border-radius: 2%;
border-style: solid;
border-width: .1em;
border-color: var(--body-fg-color-deemphasize-nontext);
padding: 0;
margin: 0 0 1em 0;
.blockquote {
padding: 0;
margin: 0;
}
}
margin: 0;
background-color: var(--body-bg-color);
border-radius: 2%;
border-style: solid;
border-width: .1em;
border-color: var(--body-fg-color-deemphasize-nontext);
padding: 1em;
font-family: sans-serif;
line-height: 1.4em;
max-width: 30rem;
a.inline-tweet-user {
text-decoration: none;
.inline-tweet-pfp {
float: left;
width: 4rem;
height: 4rem;
border-radius: 50%;
margin: 0 .5rem 0 0;
border-style: solid;
border-width: .1em;
border-color: var(--body-fg-color-deemphasize-nontext);
}
.inline-tweet-display-name {
margin: 0;
font-size: 1rem;
text-decoration: none;
color: var(--body-fg-color);
}
.inline-tweet-username {
margin: 0;
font-size: 1rem;
font-weight: normal;
color: var(--inline-tweet-username-fg-color);
}
}
.inline-tweet-id {
font-size: 70%;
color: var(--body-fg-color-deemphasize-text);
margin: 0;
padding: 0;
}
.inline-tweet-text {
clear: both;
font-size: 1rem;
}
ol.media-inline-tweet-list {
list-style-type: none;
padding: 0;
li:before {
content: "";
padding: 0;
margin: 0;
}
li {
display: inline-block;
padding: 0.25em;
margin: 0;
.media-inline-tweet {
max-width: 100%;
border-radius: 2%;
border-radius: 2%;
border-style: solid;
border-width: .1em;
border-color: var(--body-fg-color-deemphasize-nontext);
}
}
}
ol.media-inline-tweet-list-1 li {
max-width: 100%;
}
ol.media-inline-tweet-list-2 li {
max-width: 45%;
}
ol.media-inline-tweet-list-3 li {
max-width: 30%;
}
ol.media-inline-tweet-list-4 li {
max-width: 20%;
}
.inline-tweet-footer {
.inline-tweet-original-link {
.inline-tweet-dt {
font-size: .9rem;
font-family: sans-serif;
margin: 0;
padding-bottom: 1rem;
color: var(--inline-tweet-dt-fg-color);
text-decoration: none;
}
}
.inline-tweet-about-button {
float: right;
background-color: var(--inline-tweet-about-bg-color);
color: var(--inline-tweet-about-fg-color);
border-radius: 1em;
width: 2em;
height: 2em;
text-align: center;
padding: 0;
}
.inline-tweet-about-explanation {
color: var(--body-fg-color-deemphasize-text);
font-size: .8rem;
line-height: 1.2rem;
ul.inline-tweet-about-explanation-footer li {
}
}
}
}
Here’s stuff I added to the whole-site JS header layouts/partials/header.js.html
(just the JS I added):
function getDocHeight(doc) {
doc = doc || document;
// stackoverflow.com/questions/1145850/
const body = doc.body;
const html = doc.documentElement;
const height = Math.max(
body.scrollHeight,
body.offsetHeight,
html.clientHeight,
html.scrollHeight,
html.offsetHeight
);
return height;
}
function resizeEmbeddedTweets() {
const tweetHtmlObjs = document.getElementsByClassName("embedded-tweet-html-object");
for (const tweetHtmlObj of tweetHtmlObjs) {
window.TESTTWEET = tweetHtmlObj;
const tweetHeight = getDocHeight(tweetHtmlObj.contentDocument);
console.log(`tweetHeight: ${tweetHeight}`);
tweetHtmlObj.height = tweetHeight + 10;
}
}
function resizeEmbeddedTweets2() {
const tweetHtmlFrames = document.querySelectorAll("iframe.embedded-tweet-html-iframe")
for (const tweetHtmlFrame of tweetHtmlFrames) {
const objWindow = tweetHtmlFrame.contentWindow
const objDoc = objWindow.document
const objHtml = objDoc.documentElement
const objBody = objDoc.body
if(objBody) {
// objBody.style.overflowX = "scroll" // scrollbar-jitter fix
// objBody.style.overflowY = "hidden"
}
if(objHtml) {
// objHtml.style.overflowX = "scroll" // scrollbar-jitter fix
// objHtml.style.overflowY = "hidden"
// var style = window.getComputedStyle(html)
// tweetHtmlObj.width = parseInt(style.getPropertyValue("width")) // round value
// tweetHtmlObj.height = parseInt(style.getPropertyValue("height"))
// console.log(`Just set <object> height to ${tweetHtmlObj.width}x${tweetHtmlObj.height}`);
const objHtmlStyle = objWindow.getComputedStyle(objHtml);
const compW = objHtmlStyle.getPropertyValue("width");
const compH = objHtmlStyle.getPropertyValue("height");
const docHeight = getDocHeight(objDoc);
console.log(`Computed style: ${compW}x${compH}; JS detected height ${docHeight}.`);
console.log(objHtml.getBoundingClientRect())
tweetHtmlFrame.width = parseInt(compW);
tweetHtmlFrame.height = parseInt(docHeight);
}
}
}
// requestAnimationFrame(resizeEmbeddedTweets2);
// resizeEmbeddedTweets2();
window.onloads.push(resizeEmbeddedTweets2);
// window.addEventListener('resize', resizeEmbeddedTweets2);
window.addEventListener('message', function (e) {
if (e.data.mrlevent) {
console.log(`Receiving mrlevent from iframe...`)
window.TESTEVENT = e;
if (e.data.mrlevent === "resize") {
console.log(`Getting resize message from iframe with dimensions: ${e.data.w} x ${e.data.h}`);
return;
resizeEmbeddedTweets2();
}
// } else {
// console.log(`Receiving non-mrl event?`)
// console.log(e)
}
})
Result
Unsatisfying :(
- That
resizeObserver
thing seems like it ought to be handy, but it doesn’t trigger when the user clicks button that shows the about message for the tweet embed. - Measuring the height gets it wrong in every case. Not sure if differently wrong or the same wrong, but wrong.