Merge pull request 'Adds a full calendar display to the tilderadio schedule' (#13) from tomasino/tilderadio-site:master into master
continuous-integration/drone/push Build is passing Details

Reviewed-on: #13
This commit is contained in:
deepend 2020-09-27 02:15:54 +00:00
commit 7d40425445
6 changed files with 252 additions and 26 deletions

132
css/calendar.css Normal file
View File

@ -0,0 +1,132 @@
.calendar {
font-family: sans-serif;
width: 100%;
border-spacing: 0;
border-collapse: separate;
table-layout: fixed;
margin-bottom: 50px;
}
.calendar thead tr th {
background: #1c201b;
padding: 0.5em;
overflow: hidden;
text-align: center;
border-bottom: 1px solid #26d700;
}
.calendar thead tr th:first-child {
border-radius: 3px 0 0 0;
}
.calendar thead tr th:last-child {
border-radius: 0 3px 0 0;
}
.calendar thead tr th .day {
display: block;
font-size: 1.2em;
border-radius: 50%;
width: 30px;
height: 30px;
margin: 0 auto 5px;
padding: 5px;
line-height: 1.8;
}
.calendar thead tr th .day.active {
background: #d1d5db;
color: #626E7E;
}
.calendar thead tr th .short {
display: none;
}
.calendar thead tr th i {
vertical-align: middle;
font-size: 2em;
}
.calendar tbody tr {
background: #1c201b;
}
.calendar tbody tr:nth-child(odd) {
background: #313e2f;
}
.calendar tbody tr:nth-child(2n+0) td {
border-bottom: 1px solid #626E7E;
}
.calendar tbody tr td {
text-align: center;
vertical-align: middle;
border-left: 1px solid #626E7E;
position: relative;
height: 32px;
cursor: pointer;
overflow: hidden;
}
.calendar tbody tr td:last-child {
border-right: 1px solid #626E7E;
}
.calendar tbody tr td.hour {
font-size: 2em;
padding: 0;
background: #072000;
border-bottom: 1px solid #626E7E;
border-collapse: separate;
min-width: 100px;
cursor: default;
}
.calendar tbody tr td.hour span {
display: block;
}
@media (max-width: 60em) {
.calendar-wrapper {
display: block;
overflow-x: scroll;
}
.calendar {
min-width: 800px;
}
.calendar tbody tr td.hour {
font-size: 16px;
}
.calendar thead tr th .long {
display: none;
}
.calendar thead tr th .short {
display: block;
}
.calendar tbody tr td.hour span {
transform: rotate(270deg);
-webkit-transform: rotate(270deg);
-moz-transform: rotate(270deg);
}
}
@media (max-width: 27em) {
.calendar-wrapper {
display: block;
overflow-x: scroll;
}
.calendar {
min-width: 800px;
}
.calendar tbody tr td.hour {
font-size: 16px;
text-align: right;
}
.calendar thead tr th {
font-size: 65%;
}
.calendar thead tr th .day {
display: block;
font-size: 1.2em;
border-radius: 50%;
width: 20px;
height: 20px;
margin: 0 auto 5px;
padding: 5px;
}
.calendar thead tr th .day.active {
background: #d1d5db;
color: #626E7E;
}
.calendar tbody tr td.hour span {
transform: translateY(16px) rotate(270deg);
-webkit-transform: translateY(16px) rotate(270deg);
-moz-transform: translateY(16px) rotate(270deg);
}
}

View File

@ -304,7 +304,8 @@ th {
.img-thumbnail,
body {
background-color: #040304
background-color: #040304;
overflow-x: hidden;
}
@font-face {
@ -1585,7 +1586,7 @@ h6 {
.h1,
h1 {
font-size: 48px
font-size: 38px
}
.h2,
@ -1834,6 +1835,11 @@ dd {
}
@media (min-width:768px) {
.h1,
h1 {
font-size: 48px
}
.dl-horizontal dt {
float: left;
width: 160px;
@ -8014,4 +8020,4 @@ tr.active {
::-moz-selection {
background: #3EE77B;
color: #040304
}
}

View File

@ -8,6 +8,7 @@
</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="/css/hacker.css">
<link rel="stylesheet" href="/css/calendar.css">
<link rel="icon" type="image/png" href="https://tilderadio.org/logos/tilderadio-green.png"><?=isset($additional_head)?PHP_EOL." ".$additional_head.PHP_EOL:""?>
</head>

77
schedule/calendar.php Normal file
View File

@ -0,0 +1,77 @@
<section class="calendar-wrapper">
<?php
function check_in_range($start_date, $end_date, $checkdate) {
$start_ts = strtotime($start_date);
$end_ts = strtotime($end_date);
$ch_ts = strtotime($checkdate);
return (($ch_ts >= $start_ts) && ($ch_ts < $end_ts));
}
// Create a date range between the schedule start and end dates
$begin = new DateTime($schedule[0]['start']);
$end = new DateTime(end($schedule)['start']);
$daterange = new DatePeriod($begin, new DateInterval('P1D'), $end);
?>
<table class="calendar">
<thead>
<tr>
<th></th>
<?php
// Loop over our date range to draw the headers
foreach($daterange as $date){
?>
<th>
<span class="day"><?php echo $date->format("d") ?></span>
<span class="long"><?php echo $date->format("l") ?></span>
<span class="short"><?php echo $date->format("D") ?></span>
</th>
<?php
}
?>
</tr>
</thead>
<tbody>
<?php
// time will count us by 30-min increments through the day
$time = mktime(0, 0, 0, 1, 1);
// Loop over the day in 30 min increments
for ($i = 0; $i < 86400; $i += 1800) {
?>
<tr>
<?php
// Only show row if we're on a full hour block. It's a rowspan 2
if ((($i / 1800) % 2) === 0 ) {
?>
<td class="hour" rowspan="2"><span><?php echo date('H', $time + $i) ?>:00</span></td>
<?php
}
?>
<?php
// Loop over each day of the week for this 30 min span
foreach($daterange as $date){
// merge date (changing days) and time (incrementing by 30 min) to draw calendar by row.
$merge = new DateTime($date->format('Y-m-d') .' ' .date('H:i:s', $time + $i));
// We'll now use $merge to see if any shows are airing at this time
$match = false;
foreach ($schedule as $show) {
if (check_in_range($show['start'], $show['end'], $merge->format('Y-m-d H:i:s'))) {
echo "<td>" . $show['title'] . "</td>\n";
$match = true;
break;
}
}
// if no match was found, leave an empty node
if (! $match) {
echo "<td></td>\n";
}
}
?>
</tr>
<?php
}
?>
</tbody>
</table>
</section>

View File

@ -9,6 +9,10 @@ include 'schedule.php';
<p>all times in UTC. current time is <span id="utcdate"><?=formatdate("now")?></span>.</p>
<p>this schedule is also available in <a href="https://icalendar.org/validator.html?url=https://tilderadio.org/schedule/ics.php">iCalendar format</a>. point your calendar client at <code>https://tilderadio.org/schedule/ics.php</code>.</p>
<?php
include 'calendar.php';
?>
<table class="table table-striped">
<thead>
<tr>

View File

@ -2,31 +2,37 @@
include 'apikey.php';
if (empty($apikey)) {
die("missing api key");
/* If we don't have the API key, assume we're developing. Pull data from live version of this file */
$context = stream_context_create([
"http" => [
"method" => "GET",
]
]);
$schedule = json_decode(file_get_contents("https://tilderadio.org/schedule/schedule.php?json=yes", false, $context), true);
} else {
$context = stream_context_create([
"http" => [
"method" => "GET",
"header" => "X-API-Key: $apikey\r\n"
]
]);
// allow ics.php to overwrite $from and $to
if (!isset($from,$to)) {
$from = gmdate("Y-m-d\TH:i:s\Z", strtotime("now + 1 day"));
$to = gmdate("Y-m-d\TH:i:s\Z", strtotime("now + 8 days"));
}
$schedule = json_decode(
file_get_contents(
"https://radio.tildeverse.org/api/station/1/streamers/schedule?start=$from&end=$to",
false,
$context
),
true
);
}
$context = stream_context_create([
"http" => [
"method" => "GET",
"header" => "X-API-Key: $apikey\r\n"
]
]);
// allow ics.php to overwrite $from and $to
if (!isset($from,$to)) {
$from = gmdate("Y-m-d\TH:i:s\Z", strtotime("now + 1 day"));
$to = gmdate("Y-m-d\TH:i:s\Z", strtotime("now + 8 days"));
}
$schedule = json_decode(
file_get_contents(
"https://radio.tildeverse.org/api/station/1/streamers/schedule?start=$from&end=$to",
false,
$context
),
true
);
usort($schedule, function ($a, $b) {
return $a["start"] <=> $b["start"];
});