forked from tilderadio/site
Merge pull request 'Adds a full calendar display to the tilderadio schedule' (#13) from tomasino/tilderadio-site:master into master
Reviewed-on: tilderadio/site#13
This commit is contained in:
commit
7d40425445
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -304,7 +304,8 @@ th {
|
||||||
|
|
||||||
.img-thumbnail,
|
.img-thumbnail,
|
||||||
body {
|
body {
|
||||||
background-color: #040304
|
background-color: #040304;
|
||||||
|
overflow-x: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
|
@ -1585,7 +1586,7 @@ h6 {
|
||||||
|
|
||||||
.h1,
|
.h1,
|
||||||
h1 {
|
h1 {
|
||||||
font-size: 48px
|
font-size: 38px
|
||||||
}
|
}
|
||||||
|
|
||||||
.h2,
|
.h2,
|
||||||
|
@ -1834,6 +1835,11 @@ dd {
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (min-width:768px) {
|
@media (min-width:768px) {
|
||||||
|
.h1,
|
||||||
|
h1 {
|
||||||
|
font-size: 48px
|
||||||
|
}
|
||||||
|
|
||||||
.dl-horizontal dt {
|
.dl-horizontal dt {
|
||||||
float: left;
|
float: left;
|
||||||
width: 160px;
|
width: 160px;
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
</title>
|
</title>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<link rel="stylesheet" href="/css/hacker.css">
|
<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:""?>
|
<link rel="icon" type="image/png" href="https://tilderadio.org/logos/tilderadio-green.png"><?=isset($additional_head)?PHP_EOL." ".$additional_head.PHP_EOL:""?>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
|
|
|
@ -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>
|
|
@ -9,6 +9,10 @@ include 'schedule.php';
|
||||||
<p>all times in UTC. current time is <span id="utcdate"><?=formatdate("now")?></span>.</p>
|
<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>
|
<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">
|
<table class="table table-striped">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
|
|
|
@ -2,30 +2,36 @@
|
||||||
include 'apikey.php';
|
include 'apikey.php';
|
||||||
|
|
||||||
if (empty($apikey)) {
|
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" => [
|
||||||
$context = stream_context_create([
|
"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" => [
|
"http" => [
|
||||||
"method" => "GET",
|
"method" => "GET",
|
||||||
"header" => "X-API-Key: $apikey\r\n"
|
"header" => "X-API-Key: $apikey\r\n"
|
||||||
]
|
]
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// allow ics.php to overwrite $from and $to
|
// allow ics.php to overwrite $from and $to
|
||||||
if (!isset($from,$to)) {
|
if (!isset($from,$to)) {
|
||||||
$from = gmdate("Y-m-d\TH:i:s\Z", strtotime("now + 1 day"));
|
$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"));
|
$to = gmdate("Y-m-d\TH:i:s\Z", strtotime("now + 8 days"));
|
||||||
}
|
}
|
||||||
|
|
||||||
$schedule = json_decode(
|
$schedule = json_decode(
|
||||||
file_get_contents(
|
file_get_contents(
|
||||||
"https://radio.tildeverse.org/api/station/1/streamers/schedule?start=$from&end=$to",
|
"https://radio.tildeverse.org/api/station/1/streamers/schedule?start=$from&end=$to",
|
||||||
false,
|
false,
|
||||||
$context
|
$context
|
||||||
),
|
),
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
usort($schedule, function ($a, $b) {
|
usort($schedule, function ($a, $b) {
|
||||||
return $a["start"] <=> $b["start"];
|
return $a["start"] <=> $b["start"];
|
||||||
|
|
Loading…
Reference in New Issue