|
3 | 3 | * Buckets come from verifiedAge, the function the homepage cards use, so the |
4 | 4 | * summary and the cards cannot disagree. Pure: `now` is passed in. |
5 | 5 | */ |
6 | | -import { esc, verifiedAge } from "./shared.mjs"; |
| 6 | +import { esc, freshnessPageUrl, verifiedAge } from "./shared.mjs"; |
7 | 7 |
|
8 | 8 | const RECENT_DAYS = 30; |
9 | 9 | const byName = (a, b) => a.entry.name.localeCompare(b.entry.name); |
@@ -46,3 +46,108 @@ export function freshnessLineHtml(stats, stamp, href) { |
46 | 46 | parts.push(`<a href="${esc(href)}">See every check, oldest first</a>.`); |
47 | 47 | return parts.join(" "); |
48 | 48 | } |
| 49 | + |
| 50 | +const BUCKET_WORDS = { fresh: "fresh", aging: "aging", stale: "stale", unknown: "no check date" }; |
| 51 | + |
| 52 | +function recentHtml(recent, stamp) { |
| 53 | + if (!recent.length) return `<p>None in the ${RECENT_DAYS} days before ${esc(stamp)}.</p>`; |
| 54 | + const items = recent |
| 55 | + .map( |
| 56 | + (r) => |
| 57 | + `<li><a href="../entry/${esc(r.entry.id)}/">${esc(r.entry.name)}</a> <span class="verified is-fresh">${esc(r.entry.verified)} (${dayWord(r.days)})</span></li>` |
| 58 | + ) |
| 59 | + .join("\n "); |
| 60 | + return `<ul class="recent-list"> |
| 61 | + ${items} |
| 62 | + </ul>`; |
| 63 | +} |
| 64 | + |
| 65 | +function rowHtml(r) { |
| 66 | + const date = r.entry.verified ? esc(r.entry.verified) : "none"; |
| 67 | + const age = r.days === null ? "" : dayWord(r.days); |
| 68 | + return `<tr class="fresh-row" data-id="${esc(r.entry.id)}"> |
| 69 | + <td data-label="Checked">${date}</td> |
| 70 | + <td data-label="Age">${age}</td> |
| 71 | + <td data-label="Status"><span class="verified is-${r.bucket}">${BUCKET_WORDS[r.bucket]}</span></td> |
| 72 | + <td data-label="Entry"><a href="../entry/${esc(r.entry.id)}/">${esc(r.entry.name)}</a></td> |
| 73 | + <td data-label="Licence">${esc(r.entry.license)}</td> |
| 74 | + </tr>`; |
| 75 | +} |
| 76 | + |
| 77 | +export function freshnessPageHtml({ stats, site, stamp, total, hasCard }) { |
| 78 | + const url = freshnessPageUrl(site); |
| 79 | + const title = `Licence freshness | ${site.title}`; |
| 80 | + const desc = `When each licence in the catalog was last read at its source, oldest first. As of ${stamp}.`; |
| 81 | + const card = `${String(site.siteUrl).replace(/\/+$/, "")}/og-card.png`; |
| 82 | + const cardMeta = hasCard |
| 83 | + ? `<meta property="og:image" content="${esc(card)}" /> |
| 84 | + <meta name="twitter:card" content="summary_large_image" /> |
| 85 | + <meta name="twitter:image" content="${esc(card)}" />` |
| 86 | + : `<meta name="twitter:card" content="summary" />`; |
| 87 | + return `<!DOCTYPE html> |
| 88 | +<html lang="en"> |
| 89 | + <head> |
| 90 | + <meta charset="utf-8" /> |
| 91 | + <meta name="viewport" content="width=device-width, initial-scale=1" /> |
| 92 | + <title>${esc(title)}</title> |
| 93 | + <meta name="description" content="${esc(desc)}" /> |
| 94 | + <link rel="canonical" href="${esc(url)}" /> |
| 95 | + <meta property="og:type" content="website" /> |
| 96 | + <meta property="og:site_name" content="${esc(site.title)}" /> |
| 97 | + <meta property="og:title" content="${esc(title)}" /> |
| 98 | + <meta property="og:description" content="${esc(desc)}" /> |
| 99 | + <meta property="og:url" content="${esc(url)}" /> |
| 100 | + ${cardMeta} |
| 101 | + <meta name="twitter:title" content="${esc(title)}" /> |
| 102 | + <meta name="twitter:description" content="${esc(desc)}" /> |
| 103 | + <link rel="icon" href="../favicon.svg" type="image/svg+xml" /> |
| 104 | + <link rel="preconnect" href="https://fonts.googleapis.com" /> |
| 105 | + <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> |
| 106 | + <link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500&family=Public+Sans:ital,wght@0,400;0,500;0,600;0,700;1,400&display=swap" rel="stylesheet" /> |
| 107 | + <link rel="stylesheet" href="../styles.css" /> |
| 108 | + </head> |
| 109 | + <body> |
| 110 | + <a class="skip-link" href="#content">Skip to the list</a> |
| 111 | + <header class="topbar"> |
| 112 | + <a class="brand" href="../">Free Game Dev Assets</a> |
| 113 | + <nav class="topnav" aria-label="Primary"> |
| 114 | + <a href="../#catalog">Catalog</a> |
| 115 | + <a href="../#stacks">Stacks</a> |
| 116 | + <a href="../#starters">Starters</a> |
| 117 | + <a href="../#guides">Guides</a> |
| 118 | + <a href="${esc(site.repo)}" rel="noopener noreferrer">GitHub</a> |
| 119 | + </nav> |
| 120 | + </header> |
| 121 | + <main class="section entry-page freshness-page" id="content"> |
| 122 | + <nav class="breadcrumb" aria-label="Breadcrumb"> |
| 123 | + <a href="../#catalog">Catalog</a> <span aria-hidden="true">/</span> |
| 124 | + <span aria-current="page">Licence freshness</span> |
| 125 | + </nav> |
| 126 | + <h1>Licence freshness</h1> |
| 127 | + <p class="freshness-line">${freshnessLineHtml(stats, stamp, "#every-check")}</p> |
| 128 | + <div class="entry-lead"><p>An entry's verified date is when someone last read its licence at the source. Each entry's page quotes that licence with dates. Deprecated entries are not counted.</p></div> |
| 129 | + <section aria-labelledby="recent"> |
| 130 | + <h2 id="recent">Most recently checked</h2> |
| 131 | + <p>Checked in the ${RECENT_DAYS} days before ${esc(stamp)}, newest first. The catalog keeps only the latest check date, so a first check and a recheck look the same.</p> |
| 132 | + ${recentHtml(stats.recent, stamp)} |
| 133 | + </section> |
| 134 | + <section aria-labelledby="every-check"> |
| 135 | + <h2 id="every-check">Every check, oldest first</h2> |
| 136 | + <table class="fresh-table"> |
| 137 | + <thead> |
| 138 | + <tr><th scope="col">Checked</th><th scope="col">Age</th><th scope="col">Status</th><th scope="col">Entry</th><th scope="col">Licence</th></tr> |
| 139 | + </thead> |
| 140 | + <tbody> |
| 141 | + ${stats.rows.map(rowHtml).join("\n ")} |
| 142 | + </tbody> |
| 143 | + </table> |
| 144 | + </section> |
| 145 | + </main> |
| 146 | + <footer class="footer"> |
| 147 | + <p>Catalog metadata is CC0. Linked assets keep their own licenses: re-check the live source before shipping.</p> |
| 148 | + <p class="footer-stamp">Built ${esc(stamp)} from ${total} catalog entries.</p> |
| 149 | + </footer> |
| 150 | + </body> |
| 151 | +</html> |
| 152 | +`; |
| 153 | +} |
0 commit comments