A RSS feeds list using ARC components
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
html, body { | |
background: #EEE; | |
height: 100%; | |
overflow: auto; | |
font-family: arial, helvetica, sans-serif; | |
padding: 0; | |
} | |
section { | |
background-color: white; | |
border-radius: 3px; | |
box-shadow: 0 0 3px #888; | |
float: left; | |
max-width: 300px; | |
margin: 0 1em 1em 0; | |
} | |
section header { | |
background-color: #EEE; | |
overflow: hidden; | |
position: relative; | |
} | |
section header h2 { | |
margin: 0; | |
padding: 10px; | |
font-size: 1rem | |
} | |
section header button { | |
position: absolute; | |
right: 10px; | |
top: 5px; | |
width: 1em; | |
text-indent: 2em; | |
overflow: hidden; | |
border: 0; | |
background: transparent; | |
font-size: 1.2em; | |
} | |
section header button::before { | |
content: "X"; | |
display: block; | |
position: absolute; | |
left: -2em; | |
top: 0; | |
} | |
.article-body { | |
height: 400px; | |
overflow: auto; | |
color: #666; | |
} | |
article h3 { | |
margin: 0; | |
padding: 5px 10px 10px 10px; | |
} | |
article h3 a { | |
text-decoration: none; | |
color: #333; | |
} | |
section footer { | |
background-color: #EEE; | |
padding: 10px | |
} | |
.body { | |
padding: 0px 10px 10px 10px; | |
border-bottom: 1px solid #ccc; | |
} | |
body > footer { | |
position: absolute; | |
left: 0; | |
bottom: 0; | |
background-color: #AAA; | |
padding: 10px; | |
box-sizing: border-box; | |
width: 100%; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* This is a simple demo showing how you can use different components from ARC together | |
* You can get arc at https://github.com/Ariadne-CMS/arc-arc/ or with composer: | |
* | |
* composer create-project arc/arc | |
* | |
* See this gist for a simpler demo printing a single feed: | |
* https://gist.github.com/poef/dd977430dbf922d7555f | |
*/ | |
// load the composer autoloader | |
require __DIR__ . '/vendor/autoload.php'; | |
// set shorter aliases for the html and xml writer/parser | |
use \arc\html as h; | |
use \arc\xml as x; | |
// create a http proxy with caching based on the cache headers of each request | |
$client = \arc\cache::proxy( \arc\http::client(), function($params) { | |
return ( \arc\http\headers::parseCacheTime( $params['target']->responseHeaders ) ); | |
}); | |
// read a list of feeds | |
$feeds = json_decode(file_get_contents('feeds.json'),true) ?: []; | |
// create an adhoc object to render the html | |
$agg = \arc\lambda::prototype(); | |
$agg->renderItem = function($item) { | |
return h::article( | |
h::h3( h::a( [ 'href' => $item->link->nodeValue ], $item->title->nodeValue ) ), | |
h::div( [ 'class' => 'body' ], $item->description->nodeValue ) | |
); | |
}; | |
$agg->renderItems = function($items) { | |
$itemsString = ''; | |
if ( count($items) ) { | |
foreach ($items as $item ) { | |
$itemsString .= $this->renderItem($item); | |
} | |
} else { | |
$itemsString = h::div(['class' => 'warning'], 'No articles in this feed.'); | |
} | |
// h::raw makes sure the $itemsString isn't encoded/escaped when printed later | |
return h::raw($itemsString); | |
}; | |
$agg->renderFeed = function($title, $link, $index, $items) { | |
return h::section(['class' => 'feed'], | |
h::header( | |
h::h2( $title ), | |
// this button removes this feed when pressed | |
h::form(['class' => 'remove', 'method' => 'POST'], | |
h::button(['name' => 'removeFeed', 'value' => $index], 'Remove' ) | |
) | |
), | |
h::div(['class' => 'article-body'], $this->renderItems($items) ), | |
h::footer( | |
h::a( ['href' => $link], $link ) | |
) | |
); | |
}; | |
// retrieves the contents and renders them, naming is hard... | |
$agg->getFeed = function($url, $index) use ($client) { | |
$feed = $client->get($url); | |
try { | |
$rss = \arc\xml::parse($feed); | |
} catch( \Exception $e ) { | |
$rss = \arc\html::parse($feed); | |
} | |
$items = $rss->find('item'); | |
return $this->renderFeed( | |
$rss->channel->title->nodeValue, | |
$rss->channel->link->nodeValue, | |
$index, | |
$items | |
); | |
}; | |
// runs getFeed on all feeds and concatenates the results | |
$agg->render = function($feeds) { | |
return implode( | |
array_map( | |
function($feed, $index) { | |
return $this->getFeed($feed, $index); | |
}, | |
$feeds, | |
array_keys($feeds) | |
) | |
); | |
}; | |
// check if a new feed is added | |
$newFeed = \arc\hash::get('/newFeed/', $_POST); | |
if ( isset($newFeed) ) { | |
$feeds[] = $newFeed; | |
} | |
// check if a feed has been removed | |
$removeFeed = \arc\hash::get('/removeFeed/', $_POST); | |
if ( isset($removeFeed) ) { | |
unset($feeds[ $removeFeed ]); | |
} | |
// if the feeds list has changed, write it to disk | |
// this is a very unsafe way to do this, but it keeps this example short | |
if ( isset($removeFeed) || isset($newFeed) ) { | |
file_put_contents('data/feeds.json', json_encode($feeds,true)); | |
} | |
// print the full html output | |
echo h::doctype() | |
.h::html( | |
h::head( | |
h::title('RSS Aggregator'), | |
h::link(['href' => 'rsslist.css', 'rel' => 'stylesheet']) | |
), | |
h::body( | |
h::raw($aggregator->render($feeds)), | |
h::footer( | |
h::form( | |
['method' => 'POST'], | |
h::input(['name' => 'newFeed']), | |
h::button(['ype' => 'submit'], 'Add feed') | |
) | |
) | |
) | |
); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment