diff --git a/.screenshots/detail-redesign/after-adobe-reader-19-dark.png b/.screenshots/detail-redesign/after-adobe-reader-19-dark.png new file mode 100644 index 00000000..2c8abc48 Binary files /dev/null and b/.screenshots/detail-redesign/after-adobe-reader-19-dark.png differ diff --git a/.screenshots/detail-redesign/after-adobe-reader-19-light.png b/.screenshots/detail-redesign/after-adobe-reader-19-light.png new file mode 100644 index 00000000..71d75886 Binary files /dev/null and b/.screenshots/detail-redesign/after-adobe-reader-19-light.png differ diff --git a/.screenshots/detail-redesign/after-inter-light.png b/.screenshots/detail-redesign/after-inter-light.png new file mode 100644 index 00000000..9d0dd0bf Binary files /dev/null and b/.screenshots/detail-redesign/after-inter-light.png differ diff --git a/.screenshots/detail-redesign/after-juliamono-fullpage.png b/.screenshots/detail-redesign/after-juliamono-fullpage.png new file mode 100644 index 00000000..fe218554 Binary files /dev/null and b/.screenshots/detail-redesign/after-juliamono-fullpage.png differ diff --git a/.screenshots/detail-redesign/after-juliamono-light.png b/.screenshots/detail-redesign/after-juliamono-light.png new file mode 100644 index 00000000..c50075e7 Binary files /dev/null and b/.screenshots/detail-redesign/after-juliamono-light.png differ diff --git a/.screenshots/detail-redesign/after-juliamono-mobile-375.png b/.screenshots/detail-redesign/after-juliamono-mobile-375.png new file mode 100644 index 00000000..589bbd2a Binary files /dev/null and b/.screenshots/detail-redesign/after-juliamono-mobile-375.png differ diff --git a/.screenshots/detail-redesign/before-adobe-reader-19-light.png b/.screenshots/detail-redesign/before-adobe-reader-19-light.png new file mode 100644 index 00000000..6be7a247 Binary files /dev/null and b/.screenshots/detail-redesign/before-adobe-reader-19-light.png differ diff --git a/.screenshots/detail-redesign/before-juliamono-light.png b/.screenshots/detail-redesign/before-juliamono-light.png new file mode 100644 index 00000000..c60159a0 Binary files /dev/null and b/.screenshots/detail-redesign/before-juliamono-light.png differ diff --git a/docs/.vitepress/theme/style.css b/docs/.vitepress/theme/style.css index 467c2bb7..59bfbaf8 100644 --- a/docs/.vitepress/theme/style.css +++ b/docs/.vitepress/theme/style.css @@ -8,6 +8,12 @@ --fontist-beige: #bebbac; --fontist-pale: #dddac8; + --fontist-display: "Iowan Old Style", "Apple Garamond", Baskerville, Georgia, + "Times New Roman", "Droid Serif", Times, serif; + --fontist-meta: var(--vp-font-family-mono, ui-monospace, SFMono-Regular, Menlo, + monospace); + --fontist-rule: var(--vp-c-divider, rgba(60, 60, 67, 0.12)); + /* VitePress Theme Overrides - Light Mode */ --vp-c-brand-1: var(--fontist-rose); --vp-c-brand-2: #a3435a; @@ -250,3 +256,339 @@ html.dark .vp-doc [class*="language-"] { letter-spacing: 0.02em; line-height: 1.4; } + +.vp-doc:has(.formula-hero) .formula-hero { + margin: 0 0 2.5rem; + padding-bottom: 0; + border-bottom: none; +} + +.vp-doc:has(.formula-hero) .hero-eyebrow { + display: flex; + flex-wrap: wrap; + gap: 0.5rem; + margin-bottom: 1.25rem; +} + +.vp-doc:has(.formula-hero) .hero-title { + font-family: var(--fontist-display); + font-weight: 500; + font-size: clamp(2.5rem, 5vw, 4rem); + line-height: 1.02; + letter-spacing: -0.03em; + color: var(--vp-c-text-1); + margin: 0; + padding: 0; + border-bottom: none; +} + +.vp-doc:has(.formula-hero) .hero-desc { + font-size: 1.1rem; + line-height: 1.6; + color: var(--vp-c-text-2); + max-width: 65ch; + margin: 0.85rem 0 0; +} + +.vp-doc:has(.formula-hero) .detail-chip { + display: inline-flex; + align-items: center; + gap: 0.4rem; + padding: 0.22rem 0.6rem; + border: 1px solid var(--fontist-rule); + border-radius: 999px; + font-size: 0.75rem; + line-height: 1.5; + text-decoration: none; + color: var(--vp-c-text-2); + transition: border-color 0.15s ease, color 0.15s ease; +} + +.vp-doc:has(.formula-hero) .detail-chip--link:hover { + border-color: var(--fontist-rose); + color: var(--vp-c-text-1); +} + +.vp-doc:has(.formula-hero) .detail-chip-dot { + width: 5px; + height: 5px; + border-radius: 50%; + background: var(--fontist-rose); + opacity: 0.75; + flex-shrink: 0; +} + +.vp-doc:has(.formula-hero) .detail-chip-k { + font-family: var(--fontist-meta); + font-size: 0.58rem; + letter-spacing: 0.1em; + text-transform: uppercase; + color: var(--vp-c-text-3); + opacity: 0.8; +} + +.vp-doc:has(.formula-hero) .detail-chip-v { + font-weight: 500; + color: var(--vp-c-text-1); +} + +.vp-doc:has(.formula-hero) h2#install + div[class*="language-"] { + background: var(--vp-c-bg-soft); + border: 1px solid var(--fontist-rule); + border-radius: 8px; + margin: 1rem 0 0.5rem; + padding: 1rem 1.25rem; + font-size: 0.95rem; +} + +.vp-doc:has(.formula-hero) h2#install + div[class*="language-"] code { + color: var(--fontist-rose); + background: transparent; + font-size: 0.95rem; + font-family: var(--fontist-meta); +} + +.vp-doc:has(.formula-hero) h2#install + div[class*="language-"] .copy, +.vp-doc:has(.formula-hero) h2#install + div[class*="language-"] button.copy { + color: var(--vp-c-text-3); +} + +.vp-doc:has(.formula-hero) h2#install + div[class*="language-"] .lang { + color: var(--vp-c-text-3); + opacity: 0.5; +} + +.vp-doc:has(.formula-hero) .source-line { + font-family: var(--fontist-meta); + font-size: 0.75rem; + color: var(--vp-c-text-3); + margin: 0.5rem 0 0; + line-height: 1.8; +} + +.vp-doc:has(.formula-hero) .source-link { + color: var(--vp-c-text-2); + text-decoration: none; + border-bottom: 1px solid transparent; + transition: border-color 0.15s ease, color 0.15s ease; +} + +.vp-doc:has(.formula-hero) .source-link:hover { + color: var(--fontist-rose); + border-bottom-color: var(--fontist-rose); +} + +.vp-doc:has(.formula-hero) .import-meta { + color: var(--vp-c-text-3); +} + +.vp-doc:has(.formula-hero) h2 { + font-family: var(--fontist-display); + font-weight: 400; + font-size: clamp(1.4rem, 2.5vw, 1.8rem); + letter-spacing: -0.02em; + color: var(--vp-c-text-1); + margin-top: 3rem; + margin-bottom: 1rem; + padding-bottom: 0.4rem; + border-top: none; + border-bottom: 1px solid var(--fontist-rule); +} + +.vp-doc:has(.formula-hero) h2:first-of-type { + margin-top: 2rem; +} + +.vp-doc:has(.formula-hero) h3 { + font-family: var(--fontist-display); + font-weight: 500; + font-size: clamp(1.25rem, 2.5vw, 1.6rem); + letter-spacing: -0.02em; + color: var(--vp-c-text-1); + margin-top: 2.5rem; + margin-bottom: 0.25rem; + scroll-margin-top: calc(var(--vp-nav-height, 64px) + 1.5rem); +} + +.vp-doc:has(.formula-hero) h3 + p { + font-family: var(--fontist-meta); + font-size: 0.7rem; + letter-spacing: 0.02em; + color: var(--vp-c-text-3); + margin: 0 0 0.5rem; + font-style: italic; +} + +.vp-doc:has(.formula-hero) .family-jump { + display: flex; + flex-wrap: wrap; + gap: 0.35rem 0.6rem; + padding: 0.75rem 0 0.5rem; + margin-bottom: 1.5rem; + border-bottom: 1px dashed var(--fontist-rule); +} + +.vp-doc:has(.formula-hero) .family-jump-link { + font-family: var(--fontist-meta); + font-size: 0.7rem; + letter-spacing: 0.02em; + color: var(--vp-c-text-3); + text-decoration: none; + padding: 0.15rem 0.4rem; + border-radius: 3px; + transition: color 0.15s ease, background 0.15s ease; +} + +.vp-doc:has(.formula-hero) .family-jump-link:hover { + color: var(--fontist-rose); + background: var(--vp-c-brand-soft); +} + +.vp-doc:has(.formula-hero) table { + display: block; + overflow-x: auto; + -webkit-overflow-scrolling: touch; + border-collapse: collapse; + width: 100%; + font-size: 0.85rem; + margin: 0.75rem 0 1.5rem; +} + +.vp-doc:has(.formula-hero) table thead, +.vp-doc:has(.formula-hero) table tbody { + width: 100%; +} + +.vp-doc:has(.formula-hero) table th { + font-family: var(--fontist-meta); + font-weight: 500; + font-size: 0.68rem; + letter-spacing: 0.06em; + text-transform: uppercase; + color: var(--vp-c-text-3); + border: none; + border-bottom: 2px solid var(--fontist-rule); + padding: 0.6rem 0.8rem; + text-align: left; + background: transparent; +} + +.vp-doc:has(.formula-hero) table td { + border: none; + border-bottom: 1px solid var(--fontist-rule); + padding: 0.55rem 0.8rem; + vertical-align: top; + color: var(--vp-c-text-2); +} + +.vp-doc:has(.formula-hero) table td:first-child { + color: var(--vp-c-text-1); + font-weight: 500; +} + +.vp-doc:has(.formula-hero) table tr:last-child td { + border-bottom: none; +} + +.vp-doc:has(.formula-hero) .sha-value { + font-family: var(--fontist-meta); + font-size: 0.78rem; + color: var(--vp-c-text-3); +} + +.vp-doc:has(.formula-hero) .sha-copy-btn { + background: transparent; + color: var(--vp-c-text-3); + border: 1px solid var(--fontist-rule); + border-radius: 4px; + padding: 0.15rem 0.45rem; + font-size: 0.65rem; + font-family: var(--fontist-meta); + position: static; + transform: none; + opacity: 1; + transition: color 0.15s ease, border-color 0.15s ease; +} + +.vp-doc:has(.formula-hero) .sha-copy-btn:hover { + color: var(--fontist-rose); + border-color: var(--fontist-rose); + background: transparent; +} + +.vp-doc:has(.formula-hero) .sha-copy-btn.copied { + color: #28a745; + border-color: #28a745; + background: transparent; +} + +.vp-doc:has(.formula-hero) table a[href], +.vp-doc:has(.formula-hero) .source-link { + transition: color 0.15s ease; +} + +.vp-doc:has(.formula-hero) .font-filename { + max-width: 200px; +} + +.vp-doc:has(.formula-hero) details { + margin: 1rem 0; + border: 1px solid var(--fontist-rule); + border-radius: 6px; + background: var(--vp-c-bg-soft); +} + +.vp-doc:has(.formula-hero) details summary { + padding: 0.75rem 1rem; + font-family: var(--fontist-meta); + font-size: 0.78rem; + letter-spacing: 0.04em; + color: var(--vp-c-text-2); + cursor: pointer; +} + +.vp-doc:has(.formula-hero) details summary:hover { + color: var(--fontist-rose); +} + +.vp-doc:has(.formula-hero) details pre { + margin: 0; + border-radius: 0; +} + +.vp-doc:has(.formula-hero) details > div[class*="language-"] { + border-radius: 0 0 6px 6px; +} + +html.dark .vp-doc:has(.formula-hero) h2#install + div[class*="language-"] { + background: var(--vp-c-bg-soft); + border-color: var(--fontist-rule); +} + +html.dark .vp-doc:has(.formula-hero) h2#install + div[class*="language-"] code { + color: var(--fontist-rose-light); +} + +@media (max-width: 768px) { + .vp-doc:has(.formula-hero) .hero-title { + font-size: clamp(2rem, 8vw, 3rem); + } + + .vp-doc:has(.formula-hero) .detail-chip-v { + font-size: 0.7rem; + } + + .vp-doc:has(.formula-hero) table { + font-size: 0.8rem; + } + + .vp-doc:has(.formula-hero) .family-jump-link { + font-size: 0.65rem; + } +} + +@media (prefers-reduced-motion: reduce) { + .vp-doc:has(.formula-hero) * { + transition: none !important; + } +} diff --git a/docs/generate.js b/docs/generate.js index d0403eb0..4b242b08 100644 --- a/docs/generate.js +++ b/docs/generate.js @@ -28,6 +28,15 @@ function escapeBareUrls(str) { return str.replace(/(https?:)(\/\/)/g, "$1\\$2"); } +function slugify(str) { + return String(str) + .toLowerCase() + .trim() + .replace(/[^\w\s-]/g, "") + .replace(/\s+/g, "-") + .replace(/-+/g, "-"); +} + // Detect formula source type from path function detectSourceType(slug) { if (slug.startsWith("google/")) return "google"; @@ -36,18 +45,22 @@ function detectSourceType(slug) { return "manual"; } -// Generate inline SVG badge -function svgBadge(label, text, color, textWidth = 90) { - const labelWidth = 50; - const totalWidth = labelWidth + textWidth; - const labelTextX = labelWidth / 2; - const textTextX = labelWidth + textWidth / 2; - return `${label}: ${text}`; +function badgeCategory(color) { + const c = (color || "").toLowerCase(); + if (c === "#28a745") return "open"; + if (c === "#f0ad4e") return "platform"; + if (c === "#007bff") return "freely"; + if (c === "#8b5cf6") return "bundled"; + return "other"; +} + +function chipBadge(label, text, color, _textWidth) { + const cat = badgeCategory(color); + return `${label}${text}`; } const v5Tag = 'v5'; -// Get source display info - uses SVG images from /sources/ folder function getSourceInfo(type) { const sources = { google: { @@ -67,7 +80,9 @@ function getSourceInfo(type) { badge: `Expert Curated`, }, }; - return sources[type] || sources.manual; + const info = sources[type] || sources.manual; + info.chip = `Source${info.name}`; + return info; } // Comprehensive license detection @@ -103,7 +118,7 @@ function detectLicenseInfo(yaml, sourceType) { return { type: "macos", name: "Apple-only License", - badge: svgBadge("License", "Apple-only", "#f0ad4e", 120), + badge: chipBadge("License", "Apple-only", "#f0ad4e", 120), docLink: "/licenses/apple-only", spdxUrl: null, category: "platform_restricted", @@ -122,7 +137,7 @@ function detectLicenseInfo(yaml, sourceType) { return { type: "ofl", name: `SIL Open Font License 1.1${isRfn ? " (with RFN)" : ""}`, - badge: svgBadge("License", isRfn ? "OFL 1.1-RFN" : "OFL 1.1", "#28a745", isRfn ? 140 : 120), + badge: chipBadge("License", isRfn ? "OFL 1.1-RFN" : "OFL 1.1", "#28a745", isRfn ? 140 : 120), docLink: "/licenses/ofl", spdxUrl: `https://spdx.org/licenses/${spdxPath}.html`, category: "open_source", @@ -132,7 +147,7 @@ function detectLicenseInfo(yaml, sourceType) { if (spdxLicense === "APACHE-2.0") { return { type: "apache", name: "Apache License 2.0", - badge: svgBadge("License", "Apache 2.0", "#28a745", 120), + badge: chipBadge("License", "Apache 2.0", "#28a745", 120), docLink: "/licenses/apache", spdxUrl: "https://spdx.org/licenses/Apache-2.0.html", category: "open_source", isOpen: true, }; @@ -140,7 +155,7 @@ function detectLicenseInfo(yaml, sourceType) { if (spdxLicense === "MIT") { return { type: "mit", name: "MIT License", - badge: svgBadge("License", "MIT", "#28a745", 120), + badge: chipBadge("License", "MIT", "#28a745", 120), docLink: "/licenses/mit", spdxUrl: "https://spdx.org/licenses/MIT.html", category: "open_source", isOpen: true, }; @@ -148,7 +163,7 @@ function detectLicenseInfo(yaml, sourceType) { if (spdxLicense.startsWith("CC0-")) { return { type: "cc0", name: "Creative Commons Zero (Public Domain)", - badge: svgBadge("License", "CC0 1.0", "#28a745", 120), + badge: chipBadge("License", "CC0 1.0", "#28a745", 120), docLink: "/licenses/cc0", spdxUrl: `https://spdx.org/licenses/${spdxLicense}.html`, category: "open_source", isOpen: true, }; @@ -156,7 +171,7 @@ function detectLicenseInfo(yaml, sourceType) { if (spdxLicense.startsWith("CC-BY-")) { return { type: "cc-by", name: "Creative Commons Attribution", - badge: svgBadge("License", "CC BY 4.0", "#28a745", 120), + badge: chipBadge("License", "CC BY 4.0", "#28a745", 120), docLink: "/licenses/cc-by", spdxUrl: `https://spdx.org/licenses/${spdxLicense}.html`, category: "open_source", isOpen: true, }; @@ -164,7 +179,7 @@ function detectLicenseInfo(yaml, sourceType) { if (spdxLicense.startsWith("CC-BY-SA-")) { return { type: "cc-by-sa", name: "Creative Commons Attribution-ShareAlike", - badge: svgBadge("License", "CC BY-SA 4.0", "#28a745", 120), + badge: chipBadge("License", "CC BY-SA 4.0", "#28a745", 120), docLink: "/licenses/cc-by-sa", spdxUrl: `https://spdx.org/licenses/${spdxLicense}.html`, category: "open_source", isOpen: true, }; @@ -172,7 +187,7 @@ function detectLicenseInfo(yaml, sourceType) { if (spdxLicense.startsWith("GPL-") || spdxLicense.includes("GPL")) { return { type: "gpl", name: "GNU GPL (with Font Exception)", - badge: svgBadge("License", "GPL", "#28a745", 120), + badge: chipBadge("License", "GPL", "#28a745", 120), docLink: "/licenses/gpl", spdxUrl: `https://spdx.org/licenses/${spdxLicense}.html`, category: "open_source", isOpen: true, }; @@ -180,7 +195,7 @@ function detectLicenseInfo(yaml, sourceType) { if (spdxLicense.startsWith("LGPL-")) { return { type: "lgpl", name: "GNU LGPL", - badge: svgBadge("License", "LGPL", "#28a745", 120), + badge: chipBadge("License", "LGPL", "#28a745", 120), docLink: "/licenses/lgpl", spdxUrl: `https://spdx.org/licenses/${spdxLicense}.html`, category: "open_source", isOpen: true, }; @@ -188,7 +203,7 @@ function detectLicenseInfo(yaml, sourceType) { if (spdxLicense.startsWith("UBUNTU-FONT-")) { return { type: "ufl", name: "Ubuntu Font Licence 1.0", - badge: svgBadge("License", "UFL 1.0", "#28a745", 120), + badge: chipBadge("License", "UFL 1.0", "#28a745", 120), docLink: "/licenses/ufl", spdxUrl: `https://spdx.org/licenses/${spdxLicense}.html`, category: "open_source", isOpen: true, }; @@ -196,7 +211,7 @@ function detectLicenseInfo(yaml, sourceType) { if (spdxLicense.startsWith("IPA")) { return { type: "ipa", name: "IPA Font License", - badge: svgBadge("License", "IPA", "#28a745", 120), + badge: chipBadge("License", "IPA", "#28a745", 120), docLink: "/licenses/ipa", spdxUrl: `https://spdx.org/licenses/${spdxLicense}.html`, category: "open_source", isOpen: true, }; @@ -228,7 +243,7 @@ function detectLicenseInfo(yaml, sourceType) { } return { type: refType, name: spdxLicense, - badge: svgBadge("License", refBadgeText, refBadgeColor, 120), + badge: chipBadge("License", refBadgeText, refBadgeColor, 120), docLink: null, spdxUrl: isLicenseRef ? null : `https://spdx.org/licenses/${spdxLicense}.html`, category: refCategory, isOpen: refCategory === "open_source", }; @@ -254,7 +269,7 @@ function detectLicenseInfo(yaml, sourceType) { return { type: "ofl", name: "SIL Open Font License 1.1", - badge: svgBadge("License", "OFL 1.1", "#28a745", 120), + badge: chipBadge("License", "OFL 1.1", "#28a745", 120), docLink: "/licenses/ofl", spdxUrl: "https://spdx.org/licenses/OFL-1.1.html", category: "open_source", @@ -270,7 +285,7 @@ function detectLicenseInfo(yaml, sourceType) { return { type: "ufl", name: "Ubuntu Font Licence 1.0", - badge: svgBadge("License", "UFL 1.0", "#28a745", 120), + badge: chipBadge("License", "UFL 1.0", "#28a745", 120), docLink: "/licenses/ufl", spdxUrl: "https://spdx.org/licenses/Ubuntu-font-1.0.html", category: "open_source", @@ -287,7 +302,7 @@ function detectLicenseInfo(yaml, sourceType) { return { type: "gust", name: "GUST Font License", - badge: svgBadge("License", "GUST", "#28a745", 120), + badge: chipBadge("License", "GUST", "#28a745", 120), docLink: "/licenses/gust", spdxUrl: null, // Not on SPDX category: "open_source", @@ -304,7 +319,7 @@ function detectLicenseInfo(yaml, sourceType) { return { type: "lgpl", name: "GNU LGPL", - badge: svgBadge("License", "LGPL", "#28a745", 120), + badge: chipBadge("License", "LGPL", "#28a745", 120), docLink: "/licenses/lgpl", spdxUrl: "https://spdx.org/licenses/LGPL-3.0.html", category: "open_source", @@ -321,7 +336,7 @@ function detectLicenseInfo(yaml, sourceType) { return { type: "bitstream", name: "Bitstream Vera License", - badge: svgBadge("License", "Bitstream Vera", "#28a745", 120), + badge: chipBadge("License", "Bitstream Vera", "#28a745", 120), docLink: "/licenses/bitstream", spdxUrl: "https://spdx.org/licenses/Bitstream-Vera.html", category: "open_source", @@ -341,7 +356,7 @@ function detectLicenseInfo(yaml, sourceType) { return { type: "apache", name: "Apache License 2.0", - badge: svgBadge("License", "Apache 2.0", "#28a745", 120), + badge: chipBadge("License", "Apache 2.0", "#28a745", 120), docLink: "/licenses/apache", spdxUrl: "https://spdx.org/licenses/Apache-2.0.html", category: "open_source", @@ -360,7 +375,7 @@ function detectLicenseInfo(yaml, sourceType) { return { type: "mit", name: "MIT License", - badge: svgBadge("License", "MIT", "#28a745", 120), + badge: chipBadge("License", "MIT", "#28a745", 120), docLink: "/licenses/mit", spdxUrl: "https://spdx.org/licenses/MIT.html", category: "open_source", @@ -378,7 +393,7 @@ function detectLicenseInfo(yaml, sourceType) { return { type: "bsd", name: "BSD License", - badge: svgBadge("License", "BSD", "#28a745", 120), + badge: chipBadge("License", "BSD", "#28a745", 120), docLink: "/licenses/bsd", spdxUrl: "https://spdx.org/licenses/BSD-3-Clause.html", category: "open_source", @@ -397,7 +412,7 @@ function detectLicenseInfo(yaml, sourceType) { return { type: "public_domain", name: "Public Domain", - badge: svgBadge("License", "Public Domain", "#28a745", 120), + badge: chipBadge("License", "Public Domain", "#28a745", 120), docLink: "/licenses/public-domain", spdxUrl: null, // Public domain is not a license per se category: "open_source", @@ -415,7 +430,7 @@ function detectLicenseInfo(yaml, sourceType) { return { type: "cc0", name: "Creative Commons Zero (Public Domain)", - badge: svgBadge("License", "CC0 1.0", "#28a745", 120), + badge: chipBadge("License", "CC0 1.0", "#28a745", 120), docLink: "/licenses/cc0", spdxUrl: "https://spdx.org/licenses/CC0-1.0.html", category: "open_source", @@ -431,7 +446,7 @@ function detectLicenseInfo(yaml, sourceType) { return { type: "cc-by", name: "Creative Commons Attribution", - badge: svgBadge("License", "CC BY 4.0", "#28a745", 120), + badge: chipBadge("License", "CC BY 4.0", "#28a745", 120), docLink: "/licenses/cc-by", spdxUrl: "https://spdx.org/licenses/CC-BY-4.0.html", category: "open_source", @@ -447,7 +462,7 @@ function detectLicenseInfo(yaml, sourceType) { return { type: "cc-by-sa", name: "Creative Commons Attribution-ShareAlike", - badge: svgBadge("License", "CC BY-SA 4.0", "#28a745", 120), + badge: chipBadge("License", "CC BY-SA 4.0", "#28a745", 120), docLink: "/licenses/cc-by-sa", spdxUrl: "https://spdx.org/licenses/CC-BY-SA-4.0.html", category: "open_source", @@ -464,7 +479,7 @@ function detectLicenseInfo(yaml, sourceType) { return { type: "gpl", name: "GNU GPL (with Font Exception)", - badge: svgBadge("License", "GPL", "#28a745", 120), + badge: chipBadge("License", "GPL", "#28a745", 120), docLink: "/licenses/gpl", spdxUrl: "https://spdx.org/licenses/GPL-3.0.html", category: "open_source", @@ -480,7 +495,7 @@ function detectLicenseInfo(yaml, sourceType) { return { type: "ipa", name: "IPA Font License", - badge: svgBadge("License", "IPA", "#28a745", 120), + badge: chipBadge("License", "IPA", "#28a745", 120), docLink: "/licenses/ipa", spdxUrl: "https://spdx.org/licenses/IPA.html", category: "open_source", @@ -507,7 +522,7 @@ function detectLicenseInfo(yaml, sourceType) { return { type: "freeware", name: "Freeware (Personal Use Only)", - badge: svgBadge("License", "Freeware", "#007bff", 120), + badge: chipBadge("License", "Freeware", "#007bff", 120), docLink: "/licenses/freeware", spdxUrl: null, category: "freely_distributable", @@ -519,7 +534,7 @@ function detectLicenseInfo(yaml, sourceType) { return { type: "free_use", name: "Freely Usable", - badge: svgBadge("License", "Free to Use", "#28a745", 120), + badge: chipBadge("License", "Free to Use", "#28a745", 120), docLink: "/licenses/free-use", spdxUrl: null, category: "open_source", @@ -537,7 +552,7 @@ function detectLicenseInfo(yaml, sourceType) { return { type: "free_use", name: "Freely Usable", - badge: svgBadge("License", "Free to Use", "#28a745", 120), + badge: chipBadge("License", "Free to Use", "#28a745", 120), docLink: "/licenses/free-use", spdxUrl: null, category: "open_source", @@ -553,7 +568,7 @@ function detectLicenseInfo(yaml, sourceType) { return { type: "free_commercial", name: "Free for Commercial Use", - badge: svgBadge("License", "Free Commercial", "#28a745", 120), + badge: chipBadge("License", "Free Commercial", "#28a745", 120), docLink: "/licenses/free-use", spdxUrl: null, category: "open_source", @@ -575,7 +590,7 @@ function detectLicenseInfo(yaml, sourceType) { return { type: "ms_web_fonts", name: "Microsoft Web Fonts EULA", - badge: svgBadge("License", "Freely Distributable", "#007bff", 120), + badge: chipBadge("License", "Freely Distributable", "#007bff", 120), docLink: "/licenses/microsoft-web", spdxUrl: null, category: "freely_distributable", @@ -596,7 +611,7 @@ function detectLicenseInfo(yaml, sourceType) { return { type: "ms_office", name: "Microsoft Software License", - badge: svgBadge("License", "MS Software", "#8b5cf6", 120), + badge: chipBadge("License", "MS Software", "#8b5cf6", 120), docLink: "/licenses/ms-office", spdxUrl: null, category: "bundled_software", @@ -610,7 +625,7 @@ function detectLicenseInfo(yaml, sourceType) { return { type: "adobe", name: "Adobe Software License", - badge: svgBadge("License", "Adobe Software", "#8b5cf6", 120), + badge: chipBadge("License", "Adobe Software", "#8b5cf6", 120), docLink: "/licenses/adobe", spdxUrl: null, category: "bundled_software", @@ -624,7 +639,7 @@ function detectLicenseInfo(yaml, sourceType) { return { type: "bundled", name: "Software Bundle License", - badge: svgBadge("License", "Bundled Software", "#8b5cf6", 120), + badge: chipBadge("License", "Bundled Software", "#8b5cf6", 120), docLink: "/licenses/bundled", spdxUrl: null, category: "bundled_software", @@ -641,7 +656,7 @@ function detectLicenseInfo(yaml, sourceType) { return { type: "unknown", name: "License Not Specified", - badge: svgBadge("License", "Check Source", "#17a2b8", 120), + badge: chipBadge("License", "Check Source", "#17a2b8", 120), docLink: "/licenses/unknown", spdxUrl: null, category: "unknown", @@ -850,9 +865,16 @@ ${resourceEntries let fontsSection = ""; const familyNames = Object.keys(fontFamilies); if (familyNames.length > 0) { + const showFamilyIndex = familyNames.length >= 5; + const familyIndex = showFamilyIndex + ? `
\n${familyNames + .map((fn) => `${fn}`) + .join(" ")}
\n\n` + : ""; + fontsSection = `## Font Families -${familyNames +${familyIndex}${familyNames .map((familyName) => { const styles = fontFamilies[familyName]; const uniqueTypes = [...new Set(styles.map((s) => s.type))]; @@ -865,7 +887,7 @@ ${familyNames return `### ${familyName} -*${styles.length} styles: ${uniqueTypes.join(", ")}* +*${styles.length} ${styles.length === 1 ? "style" : "styles"}: ${uniqueTypes.join(", ")}*
@@ -948,11 +970,15 @@ ${[...allCopyrights] const familyCount = familyNames.length; const metaDescription = `${displayName} font package for Fontist. ${familyCount} font families, ${styleCount} styles. Install: fontist install "${formulaName}"`; - // Build badges - const badges = [licenseInfo.badge, sourceInfo.badge].join(" "); + // Build hero eyebrow chips + const heroChips = [licenseInfo.badge, sourceInfo.chip]; + if (yaml.homepage) { + const homepageLabel = yaml.homepage.replace(/^https?:\/\//, "").replace(/\/$/, ""); + heroChips.push(`Web${homepageLabel}`); + } - // Build source section - let importSourceLine = ""; + // Build source line (below install) + let importSourceText = ""; if (yaml.import_source && Object.keys(yaml.import_source).length > 0) { const is = yaml.import_source; const details = []; @@ -963,16 +989,12 @@ ${[...allCopyrights] if (is.framework_version) details.push(`framework: ${is.framework_version}`); if (is.asset_id) details.push(`asset: ${is.asset_id}`); if (is.family_id) details.push(`family: ${is.family_id}`); - importSourceLine = `\n- **Import Source** ${v5Tag}: ${details.join(" · ")}`; + importSourceText = ` · Import Source ${v5Tag}: ${details.join(" · ")}`; } - const sourceSection = `## Source - -${sourceInfo.badge} - -- **Type**: ${sourceInfo.name} -- **Formula**: [View on GitHub](${githubURL}) -${yaml.homepage ? `- **Homepage**: [${yaml.homepage}](${yaml.homepage})` : ""}${importSourceLine}`; + const heroDesc = yaml.description && yaml.description !== displayName + ? `

${escapeBareUrls(yaml.description)}

` + : ""; // Build complete markdown const md = `\ @@ -982,17 +1004,22 @@ description: "${escapeYAMLString(metaDescription)}" outline: [2, 3] --- -# ${displayName} +
+
${heroChips.join(" ")}
+

${displayName}

${heroDesc ? "\n" + heroDesc : ""} +
-${badges} - -${yaml.description && yaml.description !== displayName ? escapeBareUrls(yaml.description) + "\n" : ""}## Quick Install +## Install \`\`\`bash ${installCmd} \`\`\` -${sourceSection} +
+ +Formula YAML ↗${importSourceText} + +
${resourcesSection} ${fontsSection}