Improve web pages

This commit is contained in:
Andrea Bedini 2022-10-27 11:56:00 +08:00
parent 37022542cc
commit 72f2efc615
6 changed files with 166 additions and 103 deletions

View File

@ -85,9 +85,11 @@ buildAction
packageVersions <- getPackageVersions inputDir
makeContentsPage currentTime outputDir packageVersions
makeIndexPage outputDir
makeTimelinePage currentTime outputDir packageVersions
makeAllPackagesPage currentTime outputDir packageVersions
makeAllPackageVersionsPage currentTime outputDir packageVersions
for_ packageVersions $ makePackageVersionPage inputDir outputDir

View File

@ -4,12 +4,13 @@
{-# LANGUAGE TemplateHaskell #-}
module Foliage.Pages
( contentsPageTemplate,
timelinePageTemplate,
( allPackagesPageTemplate,
allPackageVersionsPageTemplate,
packageVersionPageTemplate,
makeContentsPage,
makeAllPackagesPage,
makePackageVersionPage,
makeTimelinePage,
makeAllPackageVersionsPage,
makeIndexPage,
)
where
@ -21,7 +22,7 @@ import Data.Ord (Down (Down))
import Data.Text.Lazy.IO.Utf8 qualified as TL
import Data.Time (UTCTime)
import Data.Time.Clock.POSIX (POSIXTime, utcTimeToPOSIXSeconds)
import Development.Shake (Action, liftIO)
import Development.Shake (Action, traced)
import Distribution.Aeson (jsonGenericPackageDescription)
import Distribution.Package (PackageIdentifier (pkgName, pkgVersion))
import Distribution.Pretty (prettyShow)
@ -36,92 +37,98 @@ import Text.Mustache (Template)
import Text.Mustache.Compile.TH (compileMustacheDir)
import Text.Mustache.Render (renderMustache)
data ContentsPageEntry = ContentsPageEntry
{ contentsPageEntryPkgId :: PackageIdentifier,
contentsPageEntryTimestamp :: UTCTime,
contentsPageEntryTimestampPosix :: POSIXTime,
contentsPageEntrySource :: PackageVersionSource,
contentsPageEntryRevision :: Maybe RevisionSpec
makeIndexPage :: FilePath -> Action ()
makeIndexPage outputDir =
traced "webpages / index" $ do
IO.createDirectoryIfMissing True outputDir
TL.writeFile (outputDir </> "index.html") $
renderMustache indexPageTemplate $
object []
data AllPackagesPageEntry = AllPackagesPageEntry
{ allPackagesPageEntryPkgId :: PackageIdentifier,
allPackagesPageEntryTimestamp :: UTCTime,
allPackagesPageEntryTimestampPosix :: POSIXTime,
allPackagesPageEntrySource :: PackageVersionSource,
allPackagesPageEntryRevision :: Maybe RevisionSpec
}
deriving stock (Generic)
deriving (ToJSON) via MyAesonEncoding ContentsPageEntry
deriving (ToJSON) via MyAesonEncoding AllPackagesPageEntry
makeContentsPage :: UTCTime -> FilePath -> [PackageVersionMeta] -> Action ()
makeContentsPage currentTime outputDir packageVersions = do
makeAllPackagesPage :: UTCTime -> FilePath -> [PackageVersionMeta] -> Action ()
makeAllPackagesPage currentTime outputDir packageVersions = do
let packages =
sortOn contentsPageEntryPkgId $
sortOn allPackagesPageEntryPkgId $
map
( ( \PackageVersionMeta {pkgId, pkgSpec = PackageVersionSpec {packageVersionTimestamp, packageVersionRevisions, packageVersionSource}} ->
ContentsPageEntry
{ contentsPageEntryPkgId = pkgId,
contentsPageEntryTimestamp = fromMaybe currentTime packageVersionTimestamp,
contentsPageEntryTimestampPosix = utcTimeToPOSIXSeconds (fromMaybe currentTime packageVersionTimestamp),
contentsPageEntrySource = packageVersionSource,
contentsPageEntryRevision = listToMaybe packageVersionRevisions
AllPackagesPageEntry
{ allPackagesPageEntryPkgId = pkgId,
allPackagesPageEntryTimestamp = fromMaybe currentTime packageVersionTimestamp,
allPackagesPageEntryTimestampPosix = utcTimeToPOSIXSeconds (fromMaybe currentTime packageVersionTimestamp),
allPackagesPageEntrySource = packageVersionSource,
allPackagesPageEntryRevision = listToMaybe packageVersionRevisions
}
)
. head
. sortOn (Down . pkgVersion . pkgId)
)
$ groupBy ((==) `on` (pkgName . pkgId)) packageVersions
liftIO $ do
IO.createDirectoryIfMissing True outputDir
IO.createDirectoryIfMissing True (outputDir </> "contents")
TL.writeFile (outputDir </> "contents" </> "index.html") $
renderMustache contentsPageTemplate $
traced "webpages / all-packages" $ do
IO.createDirectoryIfMissing True (outputDir </> "all-packages")
TL.writeFile (outputDir </> "all-packages" </> "index.html") $
renderMustache allPackagesPageTemplate $
object ["packages" .= packages]
data TimelinePageEntry
= TimelinePageEntryPackage
{ timelinePageEntryPkgId :: PackageIdentifier,
timelinePageEntryTimestamp :: UTCTime,
timelinePageEntryTimestampPosix :: POSIXTime,
timelinePageEntrySource :: PackageVersionSource
data AllPackageVersionsPageEntry
= AllPackageVersionsPageEntryPackage
{ allPackageVersionsPageEntryPkgId :: PackageIdentifier,
allPackageVersionsPageEntryTimestamp :: UTCTime,
allPackageVersionsPageEntryTimestampPosix :: POSIXTime,
allPackageVersionsPageEntrySource :: PackageVersionSource
}
| TimelinePageEntryRevision
{ timelinePageEntryPkgId :: PackageIdentifier,
timelinePageEntryTimestamp :: UTCTime,
timelinePageEntryTimestampPosix :: POSIXTime
| AllPackageVersionsPageEntryRevision
{ allPackageVersionsPageEntryPkgId :: PackageIdentifier,
allPackageVersionsPageEntryTimestamp :: UTCTime,
allPackageVersionsPageEntryTimestampPosix :: POSIXTime
}
deriving stock (Generic)
deriving (ToJSON) via MyAesonEncoding TimelinePageEntry
deriving (ToJSON) via MyAesonEncoding AllPackageVersionsPageEntry
makeTimelinePage :: UTCTime -> FilePath -> [PackageVersionMeta] -> Action ()
makeTimelinePage currentTime outputDir packageVersions = do
makeAllPackageVersionsPage :: UTCTime -> FilePath -> [PackageVersionMeta] -> Action ()
makeAllPackageVersionsPage currentTime outputDir packageVersions = do
let entries =
sortOn (Down . timelinePageEntryTimestamp) $
sortOn (Down . allPackageVersionsPageEntryTimestamp) $
foldMap
( \PackageVersionMeta {pkgId, pkgSpec = PackageVersionSpec {packageVersionTimestamp, packageVersionRevisions, packageVersionSource}} ->
TimelinePageEntryPackage
{ timelinePageEntryPkgId = pkgId,
timelinePageEntryTimestamp = fromMaybe currentTime packageVersionTimestamp,
timelinePageEntryTimestampPosix = utcTimeToPOSIXSeconds (fromMaybe currentTime packageVersionTimestamp),
timelinePageEntrySource = packageVersionSource
AllPackageVersionsPageEntryPackage
{ allPackageVersionsPageEntryPkgId = pkgId,
allPackageVersionsPageEntryTimestamp = fromMaybe currentTime packageVersionTimestamp,
allPackageVersionsPageEntryTimestampPosix = utcTimeToPOSIXSeconds (fromMaybe currentTime packageVersionTimestamp),
allPackageVersionsPageEntrySource = packageVersionSource
} :
map
( \RevisionSpec {revisionTimestamp} ->
TimelinePageEntryRevision
{ timelinePageEntryPkgId = pkgId,
timelinePageEntryTimestamp = revisionTimestamp,
timelinePageEntryTimestampPosix = utcTimeToPOSIXSeconds revisionTimestamp
AllPackageVersionsPageEntryRevision
{ allPackageVersionsPageEntryPkgId = pkgId,
allPackageVersionsPageEntryTimestamp = revisionTimestamp,
allPackageVersionsPageEntryTimestampPosix = utcTimeToPOSIXSeconds revisionTimestamp
}
)
packageVersionRevisions
)
packageVersions
liftIO $ do
IO.createDirectoryIfMissing True outputDir
IO.createDirectoryIfMissing True (outputDir </> "timeline")
TL.writeFile (outputDir </> "timeline" </> "index.html") $
renderMustache timelinePageTemplate $
traced "webpages / all-package-versions" $ do
IO.createDirectoryIfMissing True (outputDir </> "all-package-versions")
TL.writeFile (outputDir </> "all-package-versions" </> "index.html") $
renderMustache allPackageVersionsPageTemplate $
object ["entries" .= entries]
makePackageVersionPage :: FilePath -> FilePath -> PackageVersionMeta -> Action ()
makePackageVersionPage inputDir outputDir pkgMeta@PackageVersionMeta {pkgId, pkgSpec} = do
cabalFilePath <- maybe (originalCabalFile pkgMeta) pure (revisedCabalFile inputDir pkgMeta)
pkgDesc <- readGenericPackageDescription' cabalFilePath
liftIO $ do
traced ("webpages / package / " ++ prettyShow pkgId) $ do
IO.createDirectoryIfMissing True (outputDir </> "package" </> prettyShow pkgId)
TL.writeFile (outputDir </> "package" </> prettyShow pkgId </> "index.html") $
renderMustache packageVersionPageTemplate $
@ -130,11 +137,14 @@ makePackageVersionPage inputDir outputDir pkgMeta@PackageVersionMeta {pkgId, pkg
"pkgDesc" .= jsonGenericPackageDescription pkgDesc
]
contentsPageTemplate :: Template
contentsPageTemplate = $(compileMustacheDir "contents" "templates")
indexPageTemplate :: Template
indexPageTemplate = $(compileMustacheDir "index" "templates")
timelinePageTemplate :: Template
timelinePageTemplate = $(compileMustacheDir "timeline" "templates")
allPackagesPageTemplate :: Template
allPackagesPageTemplate = $(compileMustacheDir "allPackages" "templates")
allPackageVersionsPageTemplate :: Template
allPackageVersionsPageTemplate = $(compileMustacheDir "allPackageVersions" "templates")
packageVersionPageTemplate :: Template
packageVersionPageTemplate = $(compileMustacheDir "packageVersion" "templates")

View File

@ -14,21 +14,27 @@
-->
<script src="https://cdn.datatables.net/v/bs5/jq-3.6.0/dt-1.12.1/datatables.js"></script>
<title>
Index timeline
All package versions
</title>
</head>
<body>
<div class="container px-4 py-5">
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item active" aria-current="page"><a href="/timeline/">Timeline</a></li>
</ol>
</nav>
<div class="container px-3 py-5">
<ul class="nav">
<li class="nav-item">
<a class="nav-link" href="../index.html">Home</a>
</li>
<li class="nav-item">
<a class="nav-link" href="../all-packages/index.html">All packages</a>
</li>
<li class="nav-item">
<a class="nav-link active" aria-current="page" href="#">All package versions</a>
</li>
</ul>
<h1 class="py-5">
Index timeline
All package versions
</h1>
<p>
This page lists all package versions and revisions in the index.
This page lists all package versions and revisions in the repository.
</p>
<table class="table table-hover">
<thead>
@ -41,28 +47,28 @@
</thead>
<tbody>
{{#entries}}
{{#TimelinePageEntryPackage}}
{{#AllPackageVersionsPageEntryPackage}}
<tr>
<td class="col-sm-2"><a href="/package/{{timelinePageEntryPkgId}}">{{timelinePageEntryPkgId}}</a></td>
<td class="col-sm-2"><a href="../package/{{allPackageVersionsPageEntryPkgId}}">{{allPackageVersionsPageEntryPkgId}}</a></td>
<td class="col-sm-1">Version</td>
<td class="col-sm-3" data-order="{{timelinePageEntryTimestampPosix}}">{{timelinePageEntryTimestamp}}</td>
<td class="col-sm-3" data-order="{{allPackageVersionsPageEntryTimestampPosix}}">{{allPackageVersionsPageEntryTimestamp}}</td>
<td class="col-sm-6">
<dl class="row">
{{#timelinePageEntrySource}}
{{#allPackageVersionsPageEntrySource}}
{{> packageVersionSource}}
{{/timelinePageEntrySource}}
{{/allPackageVersionsPageEntrySource}}
</dl>
</td>
</tr>
{{/TimelinePageEntryPackage}}
{{#TimelinePageEntryRevision}}
{{/AllPackageVersionsPageEntryPackage}}
{{#AllPackageVersionsPageEntryRevision}}
<tr>
<td>{{timelinePageEntryPkgId}}</td>
<td>{{allPackageVersionsPageEntryPkgId}}</td>
<td>Revision</td>
<td data-order="{{timelinePageEntryTimestampPosix}}">{{timelinePageEntryTimestamp}}</td>
<td data-order="{{allPackageVersionsPageEntryTimestampPosix}}">{{allPackageVersionsPageEntryTimestamp}}</td>
<td></td>
</tr>
{{/TimelinePageEntryRevision}}
{{/AllPackageVersionsPageEntryRevision}}
{{/entries}}
</tbody>
</table>

View File

@ -12,18 +12,24 @@
<link rel="stylesheet" href="https://cdn.datatables.net/v/bs5/dt-1.12.1/datatables.min.css" integrity="sha384-4+3RMUungd+Oh0juS2Jl3yQ7mPlVfsgr10NLSsqltLXIECi9ExY4d1cTtmf9aN8E" crossorigin="anonymous">
<script src="https://cdn.datatables.net/v/bs5/jq-3.6.0/dt-1.12.1/datatables.min.js" integrity="sha384-eU1uLDC5C4YCIouMauJZjbrnSmIiICWWAPdnZjRkNnuDxG+eJFN/EhW5GlKPAIVl" crossorigin="anonymous"></script>
<title>
Index contents
All packages
</title>
</head>
<body>
<div class="container px-4 py-5">
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item active" aria-current="page"><a href="/contents/">Contents</a></li>
</ol>
</nav>
<ul class="nav">
<li class="nav-item">
<a class="nav-link" href="../index.html">Home</a>
</li>
<li class="nav-item">
<a class="nav-link active" aria-current="page" href="#">All packages</a>
</li>
<li class="nav-item">
<a class="nav-link" href="../all-package-versions/index.html">All package versions</a>
</li>
</ul>
<h1 class="py-5">
Index contents
All packages
</h1>
<p>
This page lists the latest version and revision of all packages in the index.
@ -40,22 +46,22 @@
<tbody>
{{#packages}}
<tr>
<td class="col-sm-2"><a href="/package/{{contentsPageEntryPkgId}}">{{contentsPageEntryPkgId}}</a></td>
<td class="col-sm-3" data-order="{{contentsPageEntryTimestampPosix}}">{{contentsPageEntryTimestamp}}</td>
<td class="col-sm-2"><a href="../package/{{allPackagesPageEntryPkgId}}">{{allPackagesPageEntryPkgId}}</a></td>
<td class="col-sm-3" data-order="{{allPackagesPageEntryTimestampPosix}}">{{allPackagesPageEntryTimestamp}}</td>
<td class="col-sm-6">
<dl class="row">
{{#contentsPageEntrySource}}
{{#allPackagesPageEntrySource}}
{{> packageVersionSource}}
{{/contentsPageEntrySource}}
{{/allPackagesPageEntrySource}}
</dl>
</td>
<td class="col-sm-3">
{{#contentsPageEntryRevision}}
{{#allPackagesPageEntryRevision}}
Last revision at {{revisionTimestamp}}
{{/contentsPageEntryRevision}}
{{^contentsPageEntryRevision}}
{{/allPackagesPageEntryRevision}}
{{^allPackagesPageEntryRevision}}
No revision
{{/contentsPageEntryRevision}}
{{/allPackagesPageEntryRevision}}
</td>
</tr>
{{/packages}}

36
templates/index.mustache Normal file
View File

@ -0,0 +1,36 @@
<!doctype html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/5.1.3/css/bootstrap.min.css" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/5.1.3/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
<title>
Cabal package repository
</title>
</head>
<body>
<div class="container px-4 py-5">
<ul class="nav">
<li class="nav-item">
<a class="nav-link active" aria-current="page" href="#">Home</a>
</li>
<li class="nav-item">
<a class="nav-link" href="all-packages/index.html">All packages</a>
</li>
<li class="nav-item">
<a class="nav-link" href="all-package-versions/index.html">All package versions</a>
</li>
</ul>
<h1 class="py-5">
Cabal package repository
</h1>
<p>
Cabal package repository built with <a href="https://github.com/andreabedini/foliage">foliage</a>.
</p>
</div>
</body>
</html>

View File

@ -17,14 +17,17 @@
<body>
{{#pkgDesc}}
<div class="container px-4 py-5">
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="/timeline/">Timeline</a></li>
<li class="breadcrumb-item"><a href="/timeline/?q={{name}}">{{name}}</a></li>
<li class="breadcrumb-item active" aria-current="page">{{version}}</li>
</ol>
</nav>
<h1 class="py-5">
<ul class="nav">
<li class="nav-item">
<a class="nav-link" href="../../index.html">Home</a>
</li>
<li class="nav-item">
<a class="nav-link" href="../../all-packages/index.html">All packages</a>
</li>
<li class="nav-item">
<a class="nav-link" href="../../all-package-versions/index.html">All package versions</a>
</li>
</ul> <h1 class="py-5">
{{name}}-{{version}}
</h1>
<dl class="row class="px-4 py-5">