diff --git a/doc/lib/command/render/html.py b/doc/lib/command/render/html.py
index b011b91a2..c8c2f8605 100644
--- a/doc/lib/command/render/html.py
+++ b/doc/lib/command/render/html.py
@@ -10,6 +10,7 @@ change to the tool changed nothing about the documentation, and output that is a
import os
import re
import shutil
+import struct
from common.error import ToolError
from common.log import *
@@ -74,11 +75,12 @@ class HtmlElement:
class HtmlBuilder:
"""Builds a page from the elements it holds."""
- def __init__(self, name, title, favicon, logo, description):
+ def __init__(self, name, title, favicon, card, card_size, description):
self.name = name
self.title = title
self.favicon = favicon
- self.logo = logo
+ self.card = card
+ self.card_size = card_size
self.description = description
self.body = HtmlElement("body")
@@ -149,9 +151,17 @@ class HtmlBuilder:
if self.favicon is not None:
result += ' \n' % self.favicon
- if self.logo is not None:
+ # The card is what a link to the page looks like where it is posted. It is laid out at 1200x630 because that is the frame
+ # the sites that show a preview crop to, and a card that is not that shape loses its top and bottom to the crop.
+ if self.card is not None:
+ result += ' \n' % self.card
result += ' \n'
- result += ' \n' % self.logo
+ result += ' \n' % self.card_size[0]
+ result += ' \n' % self.card_size[1]
+ result += ' \n' % self._escape(self.name)
+
+ # Without this the preview is a thumbnail beside the text rather than the card above it
+ result += ' \n'
if self.description is not None:
result += ' \n' % self._escape(self.description)
@@ -193,19 +203,18 @@ class DocHtmlPage(DocExecute):
tagline = var_store.get("project-tagline")
+ card = None if var_store.test("card", "n") else var_store.get("project-card")
+
builder = HtmlBuilder(
var_store.replace_str("{[project]}" + ("" if tagline is None else " - " + tagline)),
var_store.replace_str(title + ("" if subtitle is None else " - " + subtitle)),
var_store.get("project-favicon"),
- None if var_store.test("logo", "n") else var_store.get("project-logo"),
+ card,
+ None if card is None else _png_size(os.path.join(self.manifest.path_doc, "resource", card)),
var_store.replace_str(xml_node_field(self.root, "description", True).strip()),
)
header = builder.body.add_new("div", "page-header")
-
- if var_store.get("html-logo") is not None:
- header.add_new("div", "page-header-logo", content="{[html-logo]}")
-
header.add_new("div", "page-header-title", content=title)
if subtitle is not None:
@@ -534,6 +543,17 @@ class DocHtmlPage(DocExecute):
return element
+####################################################################################################################################
+def _png_size(file):
+ """Read what a png says it measures.
+
+ The card says its size in the page so a crawler can lay the preview out before it has the image, and the size is read from the
+ image rather than written down so the two cannot disagree."""
+
+ with open(file, "rb") as handle:
+ return struct.unpack(">II", handle.read(24)[16:24])
+
+
####################################################################################################################################
def _resource_render(text, line_comment=False):
"""A style or a script with what it says about itself taken out.
@@ -602,10 +622,10 @@ def html_render(manifest, path_doc, path_out, exe):
if favicon is not None:
shutil.copyfile(os.path.join(path_doc, "resource", favicon), os.path.join(path_out, favicon))
- logo = var_store.get("project-logo")
+ card = var_store.get("project-card")
- if logo is not None and not var_store.test("logo", "n"):
- shutil.copyfile(os.path.join(path_doc, "resource", logo), os.path.join(path_out, logo))
+ if card is not None and not var_store.test("card", "n"):
+ shutil.copyfile(os.path.join(path_doc, "resource", card), os.path.join(path_out, card))
if not var_store.test("sponsor", "n"):
path_sponsor = os.path.join(path_doc, "resource/sponsor")
diff --git a/doc/manifest.xml b/doc/manifest.xml
index 63deda5d3..a4c2a695d 100644
--- a/doc/manifest.xml
+++ b/doc/manifest.xml
@@ -8,11 +8,11 @@
/
PostgreSQL
-
- logo.png
+ card.png
logo.svg
-
- y
+
+ y
n
@@ -27,7 +27,6 @@
Copyright © 2015-{[release-year]}, The PostgreSQL Global Development Group, <a href="{[github-url-license]}">MIT License</a>. Updated {[release-date]}
-
diff --git a/doc/release.py b/doc/release.py
index 46f307901..323444dff 100755
--- a/doc/release.py
+++ b/doc/release.py
@@ -309,7 +309,7 @@ def cmd_dist(config, dev):
"--var=project-url-root=index.html",
"--exclude=metric",
"--exclude=news",
- "--var=logo=n",
+ "--var=card=n",
"--var=news=n",
"--var=sponsor=n",
]
diff --git a/doc/resource/card.png b/doc/resource/card.png
new file mode 100644
index 000000000..b136006a0
Binary files /dev/null and b/doc/resource/card.png differ
diff --git a/doc/resource/html/default.css b/doc/resource/html/default.css
index 22d2e220f..b37f3a80a 100644
--- a/doc/resource/html/default.css
+++ b/doc/resource/html/default.css
@@ -221,11 +221,6 @@ Header
font-size: 1.25rem;
}
-.page-header-logo
-{
- display: none;
-}
-
/***********************************************************************************************************************************
Menu
***********************************************************************************************************************************/
diff --git a/doc/resource/logo.png b/doc/resource/logo.png
deleted file mode 100644
index 3aa85867d..000000000
Binary files a/doc/resource/logo.png and /dev/null differ
diff --git a/test/lib/command/lint/lint.py b/test/lib/command/lint/lint.py
index f6e20d8b1..7a82cfc19 100644
--- a/test/lib/command/lint/lint.py
+++ b/test/lib/command/lint/lint.py
@@ -17,7 +17,7 @@ from common.storage import path_list_recurse
# Files that are exempt from the content checks. A binary file is an unscannable place to hide content, so each entry must be a
# deliberate, reviewable decision.
_FILE_SKIP_LIST = (
- "doc/resource/logo.png", # Project logo
+ "doc/resource/card.png", # Card shown where a link to the documentation is posted
"test/data/filecopy.table.bin", # Binary test fixture
"doc/resource/git-history.cache", # Generated from git history, contains non-ASCII author names
)
diff --git a/test/src/module/doc/command/doc_test.py b/test/src/module/doc/command/doc_test.py
index 7c2bd1a1e..2adeec946 100644
--- a/test/src/module/doc/command/doc_test.py
+++ b/test/src/module/doc/command/doc_test.py
@@ -5,6 +5,7 @@ variables the caller gave before the documents that use them."""
####################################################################################################################################
import os
+import struct
import tempfile
from harness.test import *
@@ -122,7 +123,7 @@ MANIFEST = """
pgBackRest
pgbackrest
/
- logo.png
+ card.png
logo.svg
Updated {[release-date]}
release
@@ -174,7 +175,11 @@ def _repo(path):
file_write(os.path.join(path, "doc/resource/html/default.css"), "body { color: black; }\n")
file_write(os.path.join(path, "doc/resource/html/default.js"), "// script\n")
file_write(os.path.join(path, "doc/resource/slogo.svg"), " \n")
- file_write(os.path.join(path, "doc/resource/logo.png"), "png")
+ # Only the header of the card is needed, since that is all that is read of it
+ file_write(
+ os.path.join(path, "doc/resource/card.png"),
+ b"\x89PNG\r\n\x1a\n" + struct.pack(">I", 13) + b"IHDR" + struct.pack(">II", 1200, 630),
+ )
file_write(os.path.join(path, "doc/resource/logo.svg"), "svg")
file_write(os.path.join(path, "doc/resource/sponsor/one.png"), "png")
@@ -306,7 +311,7 @@ def test_doc():
assert_equal(sorted(path_list(path_out)), ["html", "man", "markdown"])
assert_equal(
sorted(path_list(os.path.join(path_out, "html"))),
- ["default.css", "default.js", "index.html", "logo.png", "logo.svg", "slogo.svg", "sponsor", "user-guide.html"],
+ ["card.png", "default.css", "default.js", "index.html", "logo.svg", "slogo.svg", "sponsor", "user-guide.html"],
)
# What goes beside the pages is copied rather than rendered
diff --git a/test/src/module/doc/command/render/html_test.py b/test/src/module/doc/command/render/html_test.py
index 128cc32a4..c13cc40f6 100644
--- a/test/src/module/doc/command/render/html_test.py
+++ b/test/src/module/doc/command/render/html_test.py
@@ -5,6 +5,7 @@ linefeed goes is what makes one build of the documentation comparable with the n
####################################################################################################################################
import os
+import struct
import tempfile
from harness.test import *
@@ -222,7 +223,7 @@ def _page(path, key="user-guide", config=None):
def test_element():
"""A page is built as a tree of elements so the code that decides what it holds never deals with markup."""
- builder = HtmlBuilder("Name", "Title", None, None, None)
+ builder = HtmlBuilder("Name", "Title", None, None, None, None)
body = builder.body
body.add_new("div", "one", content="Content")
@@ -236,13 +237,20 @@ def test_element():
def test_builder():
"""A page says what it is."""
- builder = HtmlBuilder("pgBackRest", "Guide & More", "logo.svg", "logo.png", "How to use it.")
+ builder = HtmlBuilder("pgBackRest", "Guide & More", "logo.svg", "card.png", (1200, 630), "How to use it.")
result = builder.render(analytics=True)
assert_in("', result)
- assert_in(' ', result)
+
+ # The card says where it is and what shape it is, so a preview can be laid out before the image has been fetched
+ assert_in(' ', result)
+ assert_in(' ', result)
+ assert_in(' ', result)
+ assert_in(' ', result)
+ assert_in(' ', result)
+
assert_in(' ', result)
assert_in(' ', result)
assert_in('', result)
@@ -404,12 +412,17 @@ def test_html_render():
with tempfile.TemporaryDirectory() as path:
_doc_path(path)
- file_write(os.path.join(path, "resource/logo.png"), "png")
+ # Only the header of the card is needed, since that is all that is read of it, and a size of its own shows the page says
+ # what the file measures rather than what the tool expects it to
+ file_write(
+ os.path.join(path, "resource/card.png"),
+ b"\x89PNG\r\n\x1a\n" + struct.pack(">I", 13) + b"IHDR" + struct.pack(">II", 400, 200),
+ )
file_write(os.path.join(path, "resource/logo.svg"), "svg")
file_write(os.path.join(path, "resource/sponsor/one.png"), "png")
manifest = _manifest(path)
- manifest.var_store.add("project-logo", "logo.png")
+ manifest.var_store.add("project-card", "card.png")
manifest.var_store.add("project-favicon", "logo.svg")
path_out = os.path.join(path, "output/html")
@@ -419,10 +432,15 @@ def test_html_render():
assert_equal(
sorted(path_list(path_out)),
- ["default.css", "default.js", "index.html", "logo.png", "logo.svg", "slogo.svg", "sponsor", "user-guide.html"],
+ ["card.png", "default.css", "default.js", "index.html", "logo.svg", "slogo.svg", "sponsor", "user-guide.html"],
)
assert_equal(path_list(os.path.join(path_out, "sponsor")), ["one.png"])
+ index = file_read(os.path.join(path_out, "index.html"))
+
+ assert_in(' ', index)
+ assert_in(' ', index)
+
# The style and the script carry no comments, since the page carries them for a browser rather than for a reader, but
# where their lines fall is left alone so one build can still be compared with the next
assert_equal(file_read(os.path.join(path_out, "default.css")), "body\n{\n color: black;\n}\n")
@@ -544,14 +562,10 @@ def test_page_other():
with tempfile.TemporaryDirectory() as path:
manifest = _manifest(_doc_path(path, user_guide=OTHER_GUIDE))
- manifest.var_store.add("html-logo", " ")
render = manifest.render_get(RENDER_HTML)
page = DocHtmlPage(manifest, "user-guide", render.menu, False).process()
- # A logo of its own for the header
- assert_in('