|
4 | 4 | <head> |
5 | 5 | <meta charset="utf-8"> |
6 | 6 | <meta name="viewport" content="width=device-width, initial-scale=1"> |
7 | | - <title>{{ if .IsHome }}{{ .Site.Title }}{{ else }}{{ .Title }} - {{ .Site.Title }}{{ end }}</title> |
8 | | - <meta name="description" |
9 | | - content="{{ if .Description }}{{ .Description }}{{ else if .IsHome }}{{ .Site.Params.description }}{{ else }}{{ .Summary | truncate 155 }}{{ end }}"> |
| 7 | + |
| 8 | + {{- $brand := .Site.Params.brand | default .Site.Title -}} |
| 9 | + {{- $ogTitle := cond .IsHome .Site.Title .Title -}} |
| 10 | + {{- $title := cond .IsHome .Site.Title (printf "%s — %s" .Title $brand) -}} |
| 11 | + {{- $metaDesc := .Site.Params.description -}} |
| 12 | + {{- if .Description }}{{ $metaDesc = .Description }}{{ else if not .IsHome }}{{ $metaDesc = (.Summary | plainify | truncate 160) }}{{ end -}} |
| 13 | + {{- $socialDesc := $metaDesc -}} |
| 14 | + {{- with .Params.og_description }}{{ $socialDesc = . }}{{ end -}} |
| 15 | + {{- $ogImage := partial "og-image.html" . -}} |
| 16 | + {{- $interReg := resources.Get "fonts/Inter-Regular.ttf" | fingerprint -}} |
| 17 | + {{- $interBold := resources.Get "fonts/Inter-Bold.ttf" | fingerprint -}} |
| 18 | + |
| 19 | + <title>{{ $title }}</title> |
| 20 | + <meta name="description" content="{{ $metaDesc }}"> |
| 21 | + <link rel="canonical" href="{{ .Permalink }}"> |
| 22 | + |
| 23 | + <!-- Resource hints --> |
| 24 | + <link rel="preconnect" href="https://cdnjs.cloudflare.com" crossorigin> |
| 25 | + <link rel="preconnect" href="https://cdn.jsdelivr.net" crossorigin> |
| 26 | + <link rel="preload" href="{{ $interBold.RelPermalink }}" as="font" type="font/ttf" crossorigin> |
10 | 27 |
|
11 | 28 | <!-- Favicon --> |
12 | 29 | <link rel="icon" type="image/x-icon" href="/favicon.ico"> |
|
20 | 37 | <link rel="%s" type="%s" href="%s" title="%s" />` .Rel .MediaType.Type .Permalink $.Site.Title | safeHTML }} |
21 | 38 | {{ end -}} |
22 | 39 |
|
23 | | - <!-- Social sharing image: dynamic per-article card when `og_title` is set, |
24 | | - else `image` front matter, else the site default (see partials/og-image.html) --> |
25 | | - {{ $ogImage := partial "og-image.html" . }} |
26 | | - |
27 | 40 | <!-- Open Graph / Facebook --> |
28 | | - <meta property="og:type" content="{{ if .IsPage }}article{{ else }}website{{ end }}"> |
| 41 | + <meta property="og:type" content="{{ cond .IsPage "article" "website" }}"> |
29 | 42 | <meta property="og:url" content="{{ .Permalink }}"> |
30 | | - <meta property="og:title" content="{{ .Title }}"> |
31 | | - <meta property="og:description" |
32 | | - content="{{ if .Description }}{{ .Description }}{{ else }}{{ .Summary | truncate 155 }}{{ end }}"> |
| 43 | + <meta property="og:title" content="{{ $ogTitle }}"> |
| 44 | + <meta property="og:description" content="{{ $socialDesc }}"> |
33 | 45 | <meta property="og:site_name" content="{{ .Site.Title }}"> |
| 46 | + <meta property="og:locale" content="en_US"> |
34 | 47 | <meta property="og:image" content="{{ $ogImage }}"> |
35 | 48 | <meta property="og:image:width" content="1200"> |
36 | 49 | <meta property="og:image:height" content="630"> |
37 | | - <meta property="og:image:alt" content="{{ .Title }} — PowerShell.org, the home of the PowerShell community"> |
| 50 | + <meta property="og:image:alt" content="{{ $ogTitle }} — PowerShell.org, the home of the PowerShell community"> |
| 51 | + {{- if and .IsPage (in (slice "articles" "podcast") .Section) }} |
| 52 | + <meta property="article:published_time" content="{{ .Date.Format "2006-01-02T15:04:05Z07:00" }}"> |
| 53 | + <meta property="article:modified_time" content="{{ .Lastmod.Format "2006-01-02T15:04:05Z07:00" }}"> |
| 54 | + {{- range .Params.authors }} |
| 55 | + <meta property="article:author" content="{{ . }}"> |
| 56 | + {{- end }} |
| 57 | + {{- with .Params.categories }} |
| 58 | + <meta property="article:section" content="{{ index . 0 }}"> |
| 59 | + {{- end }} |
| 60 | + {{- range .Params.tags }} |
| 61 | + <meta property="article:tag" content="{{ . }}"> |
| 62 | + {{- end }} |
| 63 | + {{- end }} |
38 | 64 |
|
39 | 65 | <!-- Twitter --> |
40 | | - <meta property="twitter:card" content="summary_large_image"> |
41 | | - <meta property="twitter:url" content="{{ .Permalink }}"> |
42 | | - <meta property="twitter:title" content="{{ .Title }}"> |
43 | | - <meta property="twitter:description" |
44 | | - content="{{ if .Description }}{{ .Description }}{{ else }}{{ .Summary | truncate 155 }}{{ end }}"> |
45 | | - <meta property="twitter:image" content="{{ $ogImage }}"> |
46 | | - |
47 | | - <!-- CSS --> |
48 | | - <link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet"> |
| 66 | + <meta name="twitter:card" content="summary_large_image"> |
| 67 | + <meta name="twitter:url" content="{{ .Permalink }}"> |
| 68 | + <meta name="twitter:title" content="{{ $ogTitle }}"> |
| 69 | + <meta name="twitter:description" content="{{ $socialDesc }}"> |
| 70 | + <meta name="twitter:image" content="{{ $ogImage }}"> |
| 71 | + {{- with .Site.Params.twitter_handle }} |
| 72 | + <meta name="twitter:site" content="{{ . }}"> |
| 73 | + <meta name="twitter:creator" content="{{ . }}"> |
| 74 | + {{- end }} |
| 75 | + |
| 76 | + <!-- Structured data (JSON-LD) --> |
| 77 | + {{ if .IsHome }}{{ partial "schema-site.html" . }}{{ end }} |
| 78 | + {{ if and .IsPage (in (slice "articles" "podcast") .Section) }}{{ partial "schema-article.html" . }}{{ end }} |
| 79 | + |
| 80 | + <!-- CSS — Tailwind purged against the built site, minified + fingerprinted --> |
| 81 | + {{ $tailwind := resources.Get "css/tailwind.css" | minify | fingerprint }} |
| 82 | + <link href="{{ $tailwind.RelPermalink }}" rel="stylesheet"> |
49 | 83 | <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet"> |
50 | 84 | <link href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.24.1/themes/prism-tomorrow.min.css" rel="stylesheet"> |
51 | 85 | <link href="/css/alerts.css" rel="stylesheet"> |
52 | 86 | <link href="/css/code-copy.css" rel="stylesheet"> |
53 | 87 | {{ with .Site.Params.algolia }}<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@algolia/algoliasearch-netlify-frontend@1/dist/algoliasearchNetlify.css" />{{ end }} |
54 | 88 |
|
| 89 | + <!-- Self-hosted Inter (replaces render-blocking Google Fonts @import) --> |
| 90 | + <style> |
| 91 | + @font-face { font-family: 'Inter'; font-style: normal; font-weight: 400; font-display: swap; src: url('{{ $interReg.RelPermalink }}') format('truetype'); } |
| 92 | + @font-face { font-family: 'Inter'; font-style: normal; font-weight: 700; font-display: swap; src: url('{{ $interBold.RelPermalink }}') format('truetype'); } |
| 93 | + </style> |
| 94 | + |
55 | 95 | <!-- Custom CSS --> |
56 | 96 | <style> |
57 | 97 | /* Prose typography styles (Tailwind CDN doesn't include @tailwindcss/typography) */ |
|
175 | 215 | overflow: hidden; |
176 | 216 | } |
177 | 217 |
|
178 | | - /* Import Gotham or use system fallbacks */ |
179 | | - @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800;900&display=swap'); |
| 218 | + /* Inter is self-hosted via @font-face above; this is the fallback stack */ |
180 | 219 |
|
181 | 220 | /* Gotham fallback styling */ |
182 | 221 | .gotham-black { |
|
0 commit comments