mirror of
https://github.com/kellymichels/zscripts-token-savers
synced 2026-10-07 07:18:18 +00:00
feat(site): link preview for zscripts.evomedia.net, with a card in the page's own colours
The page had a title and a description and nothing else, so pasting the link anywhere rendered a bare URL. - the full og:* block with absolute URLs, plus twitter:card and a canonical the og:url agrees with - site/og-card.png, 1200x630, in the page's own dark palette so the preview and the page look like the same thing. Composed by make_og_card.py in the private tooling repo; it lives in site/ because that directory is what reaches the server. - tests/LinkPreview.Tests.ps1 The last test is the one that earned its place. The first draft of the card showed `ztests`, which is not a command in this repo - so the test extracts the z-commands named in og:image:alt and fails unless each one is a real .ps1 or .cmd at the root. A card is public copy, and public copy must not advertise a script that does not exist. CHECKSUMS.txt is untouched: the manifest covers top-level executables only, and nothing here is one. Tested: 6 new tests, verified to fail when the card advertises ztests again. Full suite 292 passed, 1 skipped. Closes #90 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
86938d0d80
commit
dae24ce446
@ -5,6 +5,26 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<title>zscripts — one-word dev commands</title>
|
<title>zscripts — one-word dev commands</title>
|
||||||
<meta name="description" content="One-word commands for AI-assisted development. Routine start, deploy, and backup chores become scripts — saving tokens and keeping the AI's context window focused on real work.">
|
<meta name="description" content="One-word commands for AI-assisted development. Routine start, deploy, and backup chores become scripts — saving tokens and keeping the AI's context window focused on real work.">
|
||||||
|
<link rel="canonical" href="https://zscripts.evomedia.net/">
|
||||||
|
|
||||||
|
<!-- Open Graph — LinkedIn, Slack and the rest build link previews from
|
||||||
|
these. The URLs must be absolute: a relative og:image is dropped by the
|
||||||
|
strict crawlers and the card renders as bare text. -->
|
||||||
|
<meta property="og:type" content="website">
|
||||||
|
<meta property="og:url" content="https://zscripts.evomedia.net/">
|
||||||
|
<meta property="og:site_name" content="Evomedia.net">
|
||||||
|
<meta property="og:title" content="zscripts — one-word dev commands">
|
||||||
|
<meta property="og:description" content="One-word commands for AI-assisted development. Routine start, deploy and backup chores become scripts, keeping the AI's context window on real work.">
|
||||||
|
<meta property="og:image" content="https://zscripts.evomedia.net/og-card.png">
|
||||||
|
<meta property="og:image:width" content="1200">
|
||||||
|
<meta property="og:image:height" content="630">
|
||||||
|
<meta property="og:image:alt" content="zscripts — one-word dev commands, over a terminal showing zdeploy, zbackup and zrestart.">
|
||||||
|
|
||||||
|
<!-- Twitter/X card, reusing the same image. -->
|
||||||
|
<meta name="twitter:card" content="summary_large_image">
|
||||||
|
<meta name="twitter:title" content="zscripts — one-word dev commands">
|
||||||
|
<meta name="twitter:description" content="One-word commands for AI-assisted development. Routine start, deploy and backup chores become scripts, keeping the AI's context window on real work.">
|
||||||
|
<meta name="twitter:image" content="https://zscripts.evomedia.net/og-card.png">
|
||||||
<style>
|
<style>
|
||||||
:root{
|
:root{
|
||||||
--bg:#0d1117; --panel:#161b22; --border:#2a313c;
|
--bg:#0d1117; --panel:#161b22; --border:#2a313c;
|
||||||
|
|||||||
BIN
site/og-card.png
Normal file
BIN
site/og-card.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 25 KiB |
90
tests/LinkPreview.Tests.ps1
Normal file
90
tests/LinkPreview.Tests.ps1
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
# Evomedia.net Token Savers - https://github.com/evomedia-net/evo.zscripts
|
||||||
|
# Created by Kelly Michels - dev@evomedia.net
|
||||||
|
# Licensed under the MIT License. See LICENSE.
|
||||||
|
|
||||||
|
# LinkPreview.Tests.ps1 - the public page renders a card, not a bare URL.
|
||||||
|
#
|
||||||
|
# Invoke-Pester .\tests
|
||||||
|
#
|
||||||
|
# Pasting zscripts.evomedia.net into LinkedIn, Slack or a message builds a card
|
||||||
|
# from the page's og:* tags. The page had a title and a description and nothing
|
||||||
|
# else, so it pasted as a bare URL.
|
||||||
|
#
|
||||||
|
# None of that is visible from here. The page is correct, the site is up, and
|
||||||
|
# the only symptom is a card somewhere else - which is why the rule is asserted
|
||||||
|
# rather than remembered.
|
||||||
|
#
|
||||||
|
# The last test is the one that earned its place: the first draft of the card
|
||||||
|
# showed `ztests`, which is not a command in this repo. A card is public copy,
|
||||||
|
# and public copy must not advertise a script that does not exist.
|
||||||
|
|
||||||
|
BeforeAll {
|
||||||
|
$script:RepoRoot = Split-Path -Parent $PSScriptRoot
|
||||||
|
$script:Page = Join-Path $script:RepoRoot "site\index.html"
|
||||||
|
$script:Card = Join-Path $script:RepoRoot "site\og-card.png"
|
||||||
|
$script:Html = [IO.File]::ReadAllText($script:Page)
|
||||||
|
|
||||||
|
function Get-Meta {
|
||||||
|
param([string]$Key)
|
||||||
|
$pattern = '<meta (?:property|name)="' + [regex]::Escape($Key) + '" content="([^"]*)">'
|
||||||
|
$m = [regex]::Match($script:Html, $pattern)
|
||||||
|
if ($m.Success) { return $m.Groups[1].Value }
|
||||||
|
return $null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Describe "zscripts.evomedia.net link preview" {
|
||||||
|
|
||||||
|
It "carries the tags a card is built from" {
|
||||||
|
foreach ($key in @('og:type', 'og:url', 'og:title', 'og:description', 'og:image')) {
|
||||||
|
Get-Meta $key | Should -Not -BeNullOrEmpty -Because "$key is what the card is made of"
|
||||||
|
}
|
||||||
|
# Without it X renders the small square variant instead of a card.
|
||||||
|
Get-Meta 'twitter:card' | Should -Be 'summary_large_image'
|
||||||
|
}
|
||||||
|
|
||||||
|
It "gives absolute URLs, which the strict crawlers require" {
|
||||||
|
foreach ($key in @('og:url', 'og:image', 'twitter:image')) {
|
||||||
|
Get-Meta $key | Should -Match '^https://'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
It "points og:url at the same place as the canonical" {
|
||||||
|
$canonical = [regex]::Match($script:Html, '<link rel="canonical" href="([^"]*)">')
|
||||||
|
$canonical.Success | Should -BeTrue
|
||||||
|
Get-Meta 'og:url' | Should -Be $canonical.Groups[1].Value
|
||||||
|
}
|
||||||
|
|
||||||
|
It "publishes the card beside the page" {
|
||||||
|
# site/ is copied to the server wholesale; a card outside it is a 404
|
||||||
|
# and the preview falls back to text.
|
||||||
|
Test-Path -LiteralPath $script:Card | Should -BeTrue
|
||||||
|
}
|
||||||
|
|
||||||
|
It "serves a card that is the size the tags claim" {
|
||||||
|
# PNG header: width and height are big-endian at offsets 16 and 20.
|
||||||
|
$bytes = [IO.File]::ReadAllBytes($script:Card)[0..23]
|
||||||
|
$width = [int]$bytes[16] * 16777216 + [int]$bytes[17] * 65536 + [int]$bytes[18] * 256 + [int]$bytes[19]
|
||||||
|
$height = [int]$bytes[20] * 16777216 + [int]$bytes[21] * 65536 + [int]$bytes[22] * 256 + [int]$bytes[23]
|
||||||
|
$width | Should -Be 1200
|
||||||
|
$height | Should -Be 630
|
||||||
|
Get-Meta 'og:image:width' | Should -Be '1200'
|
||||||
|
Get-Meta 'og:image:height' | Should -Be '630'
|
||||||
|
}
|
||||||
|
|
||||||
|
It "does not advertise a command this repo does not ship" {
|
||||||
|
$alt = Get-Meta 'og:image:alt'
|
||||||
|
$alt | Should -Not -BeNullOrEmpty
|
||||||
|
|
||||||
|
$named = [regex]::Matches($alt, '\bz[a-z_]+\b') | ForEach-Object { $_.Value } | Sort-Object -Unique
|
||||||
|
$named.Count | Should -BeGreaterThan 0 -Because 'the alt text names the commands on the card'
|
||||||
|
|
||||||
|
foreach ($cmd in $named) {
|
||||||
|
if ($cmd -eq 'zscripts') { continue } # the toolkit, not a command
|
||||||
|
$exists = @('.ps1', '.cmd') | Where-Object {
|
||||||
|
Test-Path -LiteralPath (Join-Path $script:RepoRoot "$cmd$_")
|
||||||
|
}
|
||||||
|
$exists | Should -Not -BeNullOrEmpty -Because "$cmd is on the card but is not in this repo"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user