HTML frontend part 2: game details
authorChristian Weiske <cweiske@cweiske.de>
Mon, 11 May 2020 21:44:01 +0000 (23:44 +0200)
committerChristian Weiske <cweiske@cweiske.de>
Mon, 11 May 2020 21:44:01 +0000 (23:44 +0200)
.gitignore
bin/build-html.php
bin/clean-generated.sh
data/templates/discover.tpl.php
data/templates/game.tpl.php [new file with mode: 0644]
www/ouya-discover.css
www/ouya-game.css [new file with mode: 0644]
www/ouya-logo.grey.svg [new file with mode: 0644]
www/ouya-logo.svg [new file with mode: 0644]

index da64f16..cd66da5 100644 (file)
@@ -8,3 +8,4 @@ www/api/v1/discover.json
 www/api/v1/games/*/
 www/api/v1/search-data/
 www/discover/
 www/api/v1/games/*/
 www/api/v1/search-data/
 www/discover/
+www/game/
index e1f533f..581df02 100644 (file)
@@ -4,13 +4,28 @@
  *
  * @author Christian Weiske <cweiske@cweiske.de>
  */
  *
  * @author Christian Weiske <cweiske@cweiske.de>
  */
+require_once __DIR__ . '/functions.php';
+
 $wwwDir = __DIR__ . '/../www/';
 $discoverDir = __DIR__ . '/../www/api/v1/discover-data/';
 $wwwDiscoverDir = $wwwDir . 'discover/';
 $wwwDir = __DIR__ . '/../www/';
 $discoverDir = __DIR__ . '/../www/api/v1/discover-data/';
 $wwwDiscoverDir = $wwwDir . 'discover/';
+$gameDetailsDir = __DIR__ . '/../www/api/v1/details-data/';
+$wwwGameDir = $wwwDir . 'game/';
 
 if (!is_dir($wwwDiscoverDir)) {
     mkdir($wwwDiscoverDir, 0755);
 }
 
 if (!is_dir($wwwDiscoverDir)) {
     mkdir($wwwDiscoverDir, 0755);
 }
+if (!is_dir($wwwGameDir)) {
+    mkdir($wwwGameDir, 0755);
+}
+
+foreach (glob($gameDetailsDir . '*.json') as $gameDataFile) {
+    $htmlFile = basename($gameDataFile, '.json') . '.htm';
+    file_put_contents(
+        $wwwGameDir . $htmlFile,
+        renderGameFile($gameDataFile)
+    );
+}
 
 foreach (glob($discoverDir . '*.json') as $discoverFile) {
     $htmlFile = basename($discoverFile, '.json') . '.htm';
 
 foreach (glob($discoverDir . '*.json') as $discoverFile) {
     $htmlFile = basename($discoverFile, '.json') . '.htm';
@@ -65,6 +80,13 @@ function renderDiscoverFile($discoverFile)
         $sections[] = $section;
     }
 
         $sections[] = $section;
     }
 
+    $navLinks = [];
+    if ($title == 'DISCOVER') {
+        $navLinks['../'] = 'back';
+    } else {
+        $navLinks['./'] = 'discover';
+    }
+
     $discoverTemplate = __DIR__ . '/../data/templates/discover.tpl.php';
     ob_start();
     include $discoverTemplate;
     $discoverTemplate = __DIR__ . '/../data/templates/discover.tpl.php';
     ob_start();
     include $discoverTemplate;
@@ -73,4 +95,30 @@ function renderDiscoverFile($discoverFile)
 
     return $html;
 }
 
     return $html;
 }
+
+function renderGameFile($gameDataFile)
+{
+    $json = json_decode(file_get_contents($gameDataFile));
+    $appsDir = dirname($gameDataFile, 2) . '/apps/';
+    $downloadJson = json_decode(
+        file_get_contents(
+            $appsDir . $json->version->uuid . '-download.json'
+        )
+    );
+    $apkDownloadUrl = $downloadJson->app->downloadLink;
+
+    $navLinks = [];
+    foreach ($json->genres as $genreTitle) {
+        $url = '../discover/' . categoryPath($genreTitle) . '.htm';
+        $navLinks[$url] = $genreTitle;
+    }
+
+    $gameTemplate = __DIR__ . '/../data/templates/game.tpl.php';
+    ob_start();
+    include $gameTemplate;
+    $html = ob_get_contents();
+    ob_end_clean();
+
+    return $html;
+}
 ?>
 ?>
index 0c7f375..c6a6421 100755 (executable)
@@ -6,3 +6,5 @@ rm -r www/api/v1/developers/*
 rm www/api/v1/discover-data/*
 rm www/api/v1/games/*/*
 rm www/api/v1/search-data/*
 rm www/api/v1/discover-data/*
 rm www/api/v1/games/*/*
 rm www/api/v1/search-data/*
+rm www/discover/*
+rm www/game/*
index 3c695f2..3376697 100644 (file)
@@ -2,11 +2,13 @@
 <html xmlns="http://www.w3.org/1999/xhtml">
  <head>
   <title>OUYA: <?= htmlspecialchars($title); ?></title>
 <html xmlns="http://www.w3.org/1999/xhtml">
  <head>
   <title>OUYA: <?= htmlspecialchars($title); ?></title>
+  <meta name="generator" content="stouyapi"/>
   <link rel="stylesheet" type="text/css" href="../ouya-discover.css"/>
  </head>
  <body class="discover">
   <header>
    <h1><?= htmlspecialchars($title); ?></h1>
   <link rel="stylesheet" type="text/css" href="../ouya-discover.css"/>
  </head>
  <body class="discover">
   <header>
    <h1><?= htmlspecialchars($title); ?></h1>
+   <img class="ouyalogo" src="../ouya-logo.grey.svg" alt="OUYA logo" width="20%"/>
   </header>
 
   <?php foreach ($sections as $section): ?>
   </header>
 
   <?php foreach ($sections as $section): ?>
 
   </section>
   <?php endforeach; ?>
 
   </section>
   <?php endforeach; ?>
+
+  <nav>
+   <?php foreach ($navLinks as $url => $title): ?>
+    <a rel="up" href="<?= htmlspecialchars($url) ?>"><?= htmlspecialchars($title) ?></a>
+   <?php endforeach ?>
+  </nav>
  </body>
 </html>
  </body>
 </html>
diff --git a/data/templates/game.tpl.php b/data/templates/game.tpl.php
new file mode 100644 (file)
index 0000000..6cfc2a1
--- /dev/null
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="utf-8"?>
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+  <title><?= htmlspecialchars($json->title); ?> - OUYA game</title>
+  <meta name="generator" content="stouyapi"/>
+  <link rel="stylesheet" type="text/css" href="../ouya-game.css"/>
+ </head>
+ <body class="game">
+  <header>
+   <img class="ouyalogo" src="../ouya-logo.grey.svg" alt="OUYA logo" width="20%"/>
+  </header>
+  <section class="text">
+   <h1><?= htmlspecialchars($json->title); ?></h1>
+   <dl class="meta">
+    <dt>Rating</dt>
+    <dd class="rating">
+     <span class="average average-<?= round($json->rating->average) ?>"><?= $json->rating->average ?></span>
+     <span class="count">(<?= $json->rating->count ?>)</span>
+    </dd>
+
+    <dt>Developer</dt>
+    <dd class="company">
+     <?= htmlspecialchars($json->developer->name) ?>
+    </dd>
+
+    <dt>Suggested age</dt>
+    <dd class="contentRating">
+     <?= htmlspecialchars($json->suggestedAge) ?>
+    </dd>
+
+    <dt>Number of players</dt>
+    <dd class="players">
+     <?= htmlspecialchars(implode(', ', $json->gamerNumbers)) ?>
+    </dd>
+
+    <dt>Download size</dt>
+    <dd class="size">
+     <?= number_format($json->apk->fileSize / 1024 / 1024, 2) ?> MiB
+    </dd>
+   </dl>
+
+   <p class="description">
+    <?= nl2br(htmlspecialchars($json->description)) ?>
+   </p>
+  </section>
+
+  <section class="media">
+   <h2>Screenshots</h2>
+   <div class="content">
+    <?php foreach ($json->mediaTiles as $tile): ?>
+     <?php if ($tile->type == 'image'): ?>
+      <img src="<?= htmlspecialchars($tile->urls->thumbnail) ?>" alt="Screenshot of <?= htmlspecialchars($json->title); ?>"/>
+     <?php elseif ($tile->type == 'video'): ?>
+      <video controls="">
+       <source src="<?= htmlspecialchars($tile->url) ?>"/>
+      </video>
+     <?php endif ?>
+    <?php endforeach ?>
+   </div>
+  </section>
+
+  <section class="buttons">
+   <div>
+    <a href="<?= $apkDownloadUrl ?>">Download .apk</a>
+    <p>
+     Version <?= $json->version->number ?>, published
+     <?= gmdate('Y-m-d', $json->version->publishedAt) ?>
+    </p>
+   </div>
+  </section>
+
+  <nav>
+   <?php foreach ($navLinks as $url => $title): ?>
+    <a rel="up" href="<?= htmlspecialchars($url) ?>"><?= htmlspecialchars($title) ?></a>
+   <?php endforeach ?>
+  </nav>
+ </body>
+</html>
index 82063be..3624e40 100644 (file)
@@ -18,6 +18,13 @@ header {
     width: 100%;
     padding-left: 3ex;
 }
     width: 100%;
     padding-left: 3ex;
 }
+.ouyalogo {
+    height: 3rem;
+    width: auto;
+    position: fixed;
+    top: 2ex;
+    right: 6vw;
+}
 
 h2 {
     text-shadow: 2px 2px #555;
 
 h2 {
     text-shadow: 2px 2px #555;
@@ -70,6 +77,21 @@ h3 a {
     padding-left: 2ex;
     font-size: 80%;
 }
     padding-left: 2ex;
     font-size: 80%;
 }
+
+
+nav {
+    text-align: center;
+    margin-top: 6ex;
+    margin-bottom: 2ex;
+}
+nav a {
+    color: white;
+    margin-left: 1ex;
+    margin-right: 1ex;
+}
+
+
+/* rating stars */
 .average {
     visibility: hidden;
     font-size: 0;
 .average {
     visibility: hidden;
     font-size: 0;
diff --git a/www/ouya-game.css b/www/ouya-game.css
new file mode 100644 (file)
index 0000000..eb2738d
--- /dev/null
@@ -0,0 +1,151 @@
+body {
+    background-color: #333;
+    color: #CCC;
+    font-family: sans;
+    margin: 0;
+    padding: 0;
+    padding-top: 10ex;
+    padding-left: 5ex;
+
+    display: grid;
+    grid-template-columns: 45vw 45vw;
+    grid-gap: 1.5vw;
+}
+
+header {
+    position: fixed;
+    top: 0;
+    left: 0;
+    display: block;
+    width: 100%;
+    padding-left: 3ex;
+}
+.ouyalogo {
+    height: 3rem;
+    width: auto;
+    position: fixed;
+    top: 2ex;
+    right: 6vw;
+}
+
+section.media {
+    grid-column: 1;
+    grid-row: 1;
+}
+section.text {
+    grid-column: 2;
+    grid-row: 1;
+}
+
+section.buttons {
+    grid-column: 1 / 3;
+    grid-row: 2;
+}
+nav {
+    grid-column: 1 / 3;
+    grid-row: 3;
+}
+
+.media img, .media video {
+    max-width: 100%;
+    flex-basis: 100%;
+    flex-shrink: 0;
+}
+
+
+.media h2 {
+    display: none;
+}
+.media .content {
+    overflow-x: auto;
+    display: flex;
+    flex-direction: row;
+    scroll-snap-type: x mandatory;
+}
+.media .content img, .media .content video {
+    scroll-snap-align: start;
+}
+
+
+.text h1 {
+    font-weight: normal;
+    margin-top: 0;
+}
+.text dt {
+    display: none;
+}
+.text dd {
+    display: inline;
+    margin: 0;
+    font-weight: bold;
+}
+.text dd ~ dd:before {
+    content: "|";
+    font-weight: normal;
+}
+
+.description {
+    overflow-y: auto;
+    max-height: 50vh;
+}
+
+
+.buttons a {
+    font-size: 1.5rem;
+    color: #CCC;
+}
+
+nav {
+    text-align: center;
+}
+nav a {
+    color: white;
+    margin-left: 1ex;
+    margin-right: 1ex;
+}
+
+
+/* rating stars */
+.average {
+    visibility: hidden;
+    font-size: 0;
+}
+.average:before {
+    visibility: visible;
+    font-size: 1rem;
+    color: orange;
+}
+.average:after {
+    visibility: visible;
+    font-size: 1rem;
+}
+.average-0:after {
+    content: "★★★★★";
+}
+.average-1:before {
+    content: "★";
+}
+.average-1:after {
+    content: "★★★★";
+}
+.average-2:before {
+    content: "★★";
+}
+.average-2:after {
+    content: "★★★";
+}
+.average-3:before {
+    content: "★★★";
+}
+.average-3:after {
+    content: "★★";
+}
+.average-4:before {
+    content: "★★★★";
+}
+.average-4:after {
+    content: "★";
+}
+.average-5:before {
+    content: "★★★★★";
+}
diff --git a/www/ouya-logo.grey.svg b/www/ouya-logo.grey.svg
new file mode 100644 (file)
index 0000000..19516b0
--- /dev/null
@@ -0,0 +1,95 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   sodipodi:docname="ouya-logo.svg"
+   inkscape:version="1.0rc1 (09960d6f05, 2020-04-09)"
+   id="svg4058"
+   height="200"
+   width="600"
+   version="1.1">
+  <sodipodi:namedview
+     inkscape:pagecheckerboard="true"
+     inkscape:document-rotation="0"
+     inkscape:current-layer="svg4058"
+     inkscape:window-maximized="1"
+     inkscape:window-y="33"
+     inkscape:window-x="0"
+     inkscape:cy="111.05604"
+     inkscape:cx="317.07029"
+     inkscape:zoom="2.8284271"
+     showgrid="false"
+     id="namedview13"
+     inkscape:window-height="984"
+     inkscape:window-width="1920"
+     inkscape:pageshadow="2"
+     inkscape:pageopacity="0"
+     guidetolerance="10"
+     gridtolerance="10"
+     objecttolerance="10"
+     borderopacity="1"
+     bordercolor="#666666"
+     pagecolor="#ffffff">
+    <inkscape:grid
+       id="grid14"
+       type="xygrid" />
+  </sodipodi:namedview>
+  <defs
+     id="defs4060" />
+  <metadata
+     id="metadata4063">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     id="layer1"
+     transform="matrix(0.70921753,0,0,0.70921753,16.312988,-575.43195)">
+    <g
+       id="g4050"
+       transform="translate(-32.826774,1321.6644)">
+      <path
+         inkscape:connector-curvature="0"
+         style="color:#CCCCCC;fill:none;stroke:#CCCCCC;stroke-width:11.98948383;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+         id="path2999"
+         transform="matrix(1.0008772,0,0,1.0008772,21.2686,-884.25862)"
+         d="m 227.85715,514.50507 a 81.428575,81.428575 0 1 1 -162.85715,0 81.428575,81.428575 0 1 1 162.85715,0 z" />
+      <path
+         inkscape:connector-curvature="0"
+         style="color:#CCCCCC;fill:none;stroke:#CCCCCC;stroke-width:12.00000095;stroke-linecap:round;stroke-miterlimit:4;stroke-opacity:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+         id="path2999-6"
+         d="m 423.60916,-446.45023 0.49999,87 c 0.22695,39.48771 -32.01164,71.64801 -71.5,71.64801 -39.48836,0 -71.49999,-32.01164 -71.5,-71.5 l 0,-87.14801" />
+      <path
+         inkscape:connector-curvature="0"
+         style="color:#CCCCCC;fill:none;stroke:#CCCCCC;stroke-width:12.00000095;stroke-linecap:round;stroke-miterlimit:4;stroke-opacity:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+         id="path2999-6-5"
+         d="m 603.45555,-446.45023 0.5,37.05346 c 0.53281,39.48477 -32.01164,71.648 -71.5,71.648 -39.48836,0 -71.5,-32.01163 -71.5,-71.5 l 0,-37.20146" />
+      <path
+         inkscape:connector-curvature="0"
+         style="fill:#ff0000;stroke:#CCCCCC;stroke-width:12;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+         id="path3998"
+         d="m 532.45878,-292.98077 0,-41.55194" />
+      <path
+         inkscape:connector-curvature="0"
+         style="color:#CCCCCC;fill:none;stroke:#CCCCCC;stroke-width:12.00000095;stroke-linecap:round;stroke-miterlimit:4;stroke-opacity:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+         id="path2999-6-43"
+         d="m 636.82793,-292.45023 -0.5,-81.9747 c -0.24085,-39.48763 32.01164,-71.648 71.5,-71.648 39.48836,0 71.5,32.01163 71.5,71.49999 l 0,82.12271" />
+      <path
+         inkscape:connector-curvature="0"
+         style="fill:#ff0000;stroke:#CCCCCC;stroke-width:12;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+         id="path3998-9"
+         d="m 637.16323,-345.75021 140.57043,0" />
+    </g>
+  </g>
+</svg>
diff --git a/www/ouya-logo.svg b/www/ouya-logo.svg
new file mode 100644 (file)
index 0000000..6d075e2
--- /dev/null
@@ -0,0 +1,95 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   sodipodi:docname="ouya-logo.svg"
+   inkscape:version="1.0rc1 (09960d6f05, 2020-04-09)"
+   id="svg4058"
+   height="200"
+   width="600"
+   version="1.1">
+  <sodipodi:namedview
+     inkscape:pagecheckerboard="true"
+     inkscape:document-rotation="0"
+     inkscape:current-layer="svg4058"
+     inkscape:window-maximized="1"
+     inkscape:window-y="33"
+     inkscape:window-x="0"
+     inkscape:cy="111.05604"
+     inkscape:cx="317.07029"
+     inkscape:zoom="2.8284271"
+     showgrid="false"
+     id="namedview13"
+     inkscape:window-height="984"
+     inkscape:window-width="1920"
+     inkscape:pageshadow="2"
+     inkscape:pageopacity="0"
+     guidetolerance="10"
+     gridtolerance="10"
+     objecttolerance="10"
+     borderopacity="1"
+     bordercolor="#666666"
+     pagecolor="#ffffff">
+    <inkscape:grid
+       id="grid14"
+       type="xygrid" />
+  </sodipodi:namedview>
+  <defs
+     id="defs4060" />
+  <metadata
+     id="metadata4063">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     id="layer1"
+     transform="matrix(0.70921753,0,0,0.70921753,16.312988,-575.43195)">
+    <g
+       id="g4050"
+       transform="translate(-32.826774,1321.6644)">
+      <path
+         inkscape:connector-curvature="0"
+         style="color:#000000;fill:none;stroke:#000000;stroke-width:11.98948383;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+         id="path2999"
+         transform="matrix(1.0008772,0,0,1.0008772,21.2686,-884.25862)"
+         d="m 227.85715,514.50507 a 81.428575,81.428575 0 1 1 -162.85715,0 81.428575,81.428575 0 1 1 162.85715,0 z" />
+      <path
+         inkscape:connector-curvature="0"
+         style="color:#000000;fill:none;stroke:#000000;stroke-width:12.00000095;stroke-linecap:round;stroke-miterlimit:4;stroke-opacity:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+         id="path2999-6"
+         d="m 423.60916,-446.45023 0.49999,87 c 0.22695,39.48771 -32.01164,71.64801 -71.5,71.64801 -39.48836,0 -71.49999,-32.01164 -71.5,-71.5 l 0,-87.14801" />
+      <path
+         inkscape:connector-curvature="0"
+         style="color:#000000;fill:none;stroke:#000000;stroke-width:12.00000095;stroke-linecap:round;stroke-miterlimit:4;stroke-opacity:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+         id="path2999-6-5"
+         d="m 603.45555,-446.45023 0.5,37.05346 c 0.53281,39.48477 -32.01164,71.648 -71.5,71.648 -39.48836,0 -71.5,-32.01163 -71.5,-71.5 l 0,-37.20146" />
+      <path
+         inkscape:connector-curvature="0"
+         style="fill:#ff0000;stroke:#000000;stroke-width:12;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+         id="path3998"
+         d="m 532.45878,-292.98077 0,-41.55194" />
+      <path
+         inkscape:connector-curvature="0"
+         style="color:#000000;fill:none;stroke:#000000;stroke-width:12.00000095;stroke-linecap:round;stroke-miterlimit:4;stroke-opacity:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+         id="path2999-6-43"
+         d="m 636.82793,-292.45023 -0.5,-81.9747 c -0.24085,-39.48763 32.01164,-71.648 71.5,-71.648 39.48836,0 71.5,32.01163 71.5,71.49999 l 0,82.12271" />
+      <path
+         inkscape:connector-curvature="0"
+         style="fill:#ff0000;stroke:#000000;stroke-width:12;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+         id="path3998-9"
+         d="m 637.16323,-345.75021 140.57043,0" />
+    </g>
+  </g>
+</svg>