feat: commit initial

This commit is contained in:
Kazhnuz Klappsthul 2023-11-08 13:51:09 +01:00
parent c1db0a6519
commit 8ed27367a8
15 changed files with 525 additions and 0 deletions

BIN
assets/bg1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

BIN
assets/bg2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

BIN
assets/bg3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

BIN
assets/fanstuffgarden.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
assets/pics.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

BIN
assets/picsfooter.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 702 B

BIN
favicon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 740 B

273
feed.php Normal file
View File

@ -0,0 +1,273 @@
<?php
/**
* RSS for PHP - small and easy-to-use library for consuming an RSS Feed
*
* @copyright Copyright (c) 2008 David Grudl
* @license New BSD License
* @version 1.5
*/
class Feed
{
/** @var int */
public static $cacheExpire = '1 day';
/** @var string */
public static $cacheDir;
/** @var string */
public static $userAgent = 'FeedFetcher-Google';
/** @var SimpleXMLElement */
protected $xml;
/**
* Loads RSS or Atom feed.
* @param string
* @param string
* @param string
* @return Feed
* @throws FeedException
*/
public static function load($url, $user = null, $pass = null)
{
$xml = self::loadXml($url, $user, $pass);
if ($xml->channel) {
return self::fromRss($xml);
} else {
return self::fromAtom($xml);
}
}
/**
* Loads RSS feed.
* @param string RSS feed URL
* @param string optional user name
* @param string optional password
* @return Feed
* @throws FeedException
*/
public static function loadRss($url, $user = null, $pass = null)
{
return self::fromRss(self::loadXml($url, $user, $pass));
}
/**
* Loads Atom feed.
* @param string Atom feed URL
* @param string optional user name
* @param string optional password
* @return Feed
* @throws FeedException
*/
public static function loadAtom($url, $user = null, $pass = null)
{
return self::fromAtom(self::loadXml($url, $user, $pass));
}
private static function fromRss(SimpleXMLElement $xml)
{
if (!$xml->channel) {
throw new FeedException('Invalid feed.');
}
self::adjustNamespaces($xml);
foreach ($xml->channel->item as $item) {
// converts namespaces to dotted tags
self::adjustNamespaces($item);
// generate 'url' & 'timestamp' tags
$item->url = (string) $item->link;
if (isset($item->{'dc:date'})) {
$item->timestamp = strtotime($item->{'dc:date'});
} elseif (isset($item->pubDate)) {
$item->timestamp = strtotime($item->pubDate);
}
}
$feed = new self;
$feed->xml = $xml->channel;
return $feed;
}
private static function fromAtom(SimpleXMLElement $xml)
{
if (!in_array('http://www.w3.org/2005/Atom', $xml->getDocNamespaces(), true)
&& !in_array('http://purl.org/atom/ns#', $xml->getDocNamespaces(), true)
) {
throw new FeedException('Invalid feed.');
}
// generate 'url' & 'timestamp' tags
foreach ($xml->entry as $entry) {
$entry->url = (string) $entry->link['href'];
$entry->timestamp = strtotime($entry->updated);
}
$feed = new self;
$feed->xml = $xml;
return $feed;
}
/**
* Returns property value. Do not call directly.
* @param string tag name
* @return SimpleXMLElement
*/
public function __get($name)
{
return $this->xml->{$name};
}
/**
* Sets value of a property. Do not call directly.
* @param string property name
* @param mixed property value
* @return void
*/
public function __set($name, $value)
{
throw new Exception("Cannot assign to a read-only property '$name'.");
}
/**
* Converts a SimpleXMLElement into an array.
* @param SimpleXMLElement
* @return array
*/
public function toArray(SimpleXMLElement $xml = null)
{
if ($xml === null) {
$xml = $this->xml;
}
if (!$xml->children()) {
return (string) $xml;
}
$arr = [];
foreach ($xml->children() as $tag => $child) {
if (count($xml->$tag) === 1) {
$arr[$tag] = $this->toArray($child);
} else {
$arr[$tag][] = $this->toArray($child);
}
}
return $arr;
}
/**
* Load XML from cache or HTTP.
* @param string
* @param string
* @param string
* @return SimpleXMLElement
* @throws FeedException
*/
private static function loadXml($url, $user, $pass)
{
$e = self::$cacheExpire;
$cacheFile = self::$cacheDir . '/feed.' . md5(serialize(func_get_args())) . '.xml';
if (self::$cacheDir
&& (time() - @filemtime($cacheFile) <= (is_string($e) ? strtotime($e) - time() : $e))
&& $data = @file_get_contents($cacheFile)
) {
// ok
} elseif ($data = trim(self::httpRequest($url, $user, $pass))) {
if (self::$cacheDir) {
file_put_contents($cacheFile, $data);
}
} elseif (self::$cacheDir && $data = @file_get_contents($cacheFile)) {
// ok
} else {
throw new FeedException('Cannot load feed.');
}
return new SimpleXMLElement($data, LIBXML_NOWARNING | LIBXML_NOERROR | LIBXML_NOCDATA);
}
/**
* Process HTTP request.
* @param string
* @param string
* @param string
* @return string|false
* @throws FeedException
*/
private static function httpRequest($url, $user, $pass)
{
if (extension_loaded('curl')) {
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $url);
if ($user !== null || $pass !== null) {
curl_setopt($curl, CURLOPT_USERPWD, "$user:$pass");
}
curl_setopt($curl, CURLOPT_USERAGENT, self::$userAgent); // some feeds require a user agent
curl_setopt($curl, CURLOPT_HEADER, false);
curl_setopt($curl, CURLOPT_TIMEOUT, 20);
curl_setopt($curl, CURLOPT_ENCODING, '');
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); // no echo, just return result
curl_setopt($curl, CURLOPT_USERAGENT, '');
if (!ini_get('open_basedir')) {
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true); // sometime is useful :)
}
$result = curl_exec($curl);
return curl_errno($curl) === 0 && curl_getinfo($curl, CURLINFO_HTTP_CODE) === 200
? $result
: false;
} else {
$context = null;
if ($user !== null && $pass !== null) {
$options = [
'http' => [
'method' => 'GET',
'header' => 'Authorization: Basic ' . base64_encode($user . ':' . $pass) . "\r\n",
],
];
$context = stream_context_create($options);
}
return file_get_contents($url, false, $context);
}
}
/**
* Generates better accessible namespaced tags.
* @param SimpleXMLElement
* @return void
*/
private static function adjustNamespaces($el)
{
foreach ($el->getNamespaces(true) as $prefix => $ns) {
if ($prefix === '') {
continue;
}
$children = $el->children($ns);
foreach ($children as $tag => $content) {
$el->{$prefix . ':' . $tag} = $content;
}
}
}
}
/**
* An exception generated by Feed.
*/
class FeedException extends Exception
{
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

90
index.php Normal file
View File

@ -0,0 +1,90 @@
<?php
header('Content-Type: text/html; charset=utf-8');
if (!ini_get('date.timezone')) {
date_default_timezone_set('Europe/Paris');
}
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
require_once 'feed.php';
$rssSonic = Feed::loadRss('https://shaarli.kazhnuz.space/feed/rss?&searchtags=Sonic');
$rssSEGA = Feed::loadRss('https://shaarli.kazhnuz.space/feed/rss?&searchtags=SEGA');
?>
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Press Garden Zone</title>
<link rel="stylesheet" href="./style.css">
<link rel="icon" href="./favicon.png">
</head>
<body>
<header>
<nav>
<ul>
<li><a href="#" class="active" id="link-sonic">Sonic</a></li>
<li><a href="#" id="link-sega">SEGA</a></li>
</ul>
</nav>
</header>
<main>
<h1 id="head">Press Garden Zone</h1>
<section class="shown" id="section-sonic">
<?php $i = 1; ?>
<?php foreach ($rssSonic->item as $item): ?>
<?php if ($i <= 8) { ?>
<article>
<h2><a href="<?php echo htmlspecialchars($item->url) ?>"><?php echo htmlspecialchars($item->title) ?></a>
<small><?php echo date('j.n.Y H:i', (int) $item->timestamp) ?></small></h2>
<div><?php echo $item->description ?></div>
</article>
<?php } ?>
<?php endforeach ?>
<div class="btn-area"><a class="btn" href="https://shaarli.kazhnuz.space/?searchtags=Sonic"> Plus ancien articles </a></div>
</section>
<section id="section-sega">
<?php foreach ($rssSEGA->item as $item): ?>
<article>
<h2><a href="<?php echo htmlspecialchars($item->url) ?>"><?php echo htmlspecialchars($item->title) ?></a>
<small><?php echo date('j.n.Y H:i', (int) $item->timestamp) ?></small></h2>
<div><?php echo $item->description ?></div>
</article>
<?php endforeach ?>
<div class="btn-area"><a class="btn" href="https://shaarli.kazhnuz.space/?searchtags=SEGA"> Plus ancien articles </a></div>
</section>
</main>
<footer>
<p>Press Garden est une petite page servant juste à afficher les flux RSS Sonic et SEGA du <a href="https://shaarli.kazhnuz.space/">shaarli de Kazhnuz</a>.</p>
<p>Ce site est hébergé par Fanstuff Garden.</p>
<p><a href="https://fanstuff.garden"><img src="assets/fanstuffgarden.gif" /></a></p>
</footer>
<script>
const sectionSonic = document.getElementById('section-sonic');
const linkSonic = document.getElementById('link-sonic');
const sectionSEGA = document.getElementById('section-sega');
const linkSEGA = document.getElementById('link-sega');
linkSonic.addEventListener('click', function () {
linkSEGA.classList.remove('active');
linkSonic.classList.add('active');
sectionSEGA.classList.remove('shown');
sectionSonic.classList.add('shown');
});
linkSEGA.addEventListener('click', function () {
linkSEGA.classList.add('active');
linkSonic.classList.remove('active');
sectionSEGA.classList.add('shown');
sectionSonic.classList.remove('shown');
});
</script>
</body>
</html>

162
style.css Normal file
View File

@ -0,0 +1,162 @@
@font-face {
font-family: 'Teko';
src: url('fonts/teko-light-webfont.woff');
font-weight: 300;
}
@font-face {
font-family: 'Teko';
src: url('fonts/teko-regular-webfont.woff');
font-weight: 400;
}
@font-face {
font-family: 'Teko';
src: url('fonts/teko-medium-webfont.woff');
font-weight: 500;
}
@font-face {
font-family: 'Teko';
src: url('fonts/teko-semibold-webfont.woff');
font-weight: 600;
}
@font-face {
font-family: 'Teko';
src: url('fonts/teko-bold-webfont.woff');
font-weight: 700;
}
body {
background-image: url("assets/bg3.png"), url("assets/bg2.png"), url("assets/bg1.png");
background-attachment: fixed, fixed, fixed;
font-family: Inter,Cantarell,-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen,Ubuntu,'Fira Sans','Droid Sans','Helvetica Neue',sans-serif;
}
body, html {
margin: 0;
padding: 0;
}
article {
background-color: white;
border-radius: 8px;
padding: 0.5rem 1rem 1rem 1rem;
margin-bottom: 1rem;
box-shadow: 0px 1px 1px 1px rgba(0, 0, 0, 0.3);
border-left: 8px solid #e67700;
}
article:last-child {
margin-bottom: 0rem;
}
header nav {
background-color: #1971c2;
padding: 0.4rem!important;
}
main {
background-image: url("assets/pics.png"), url("assets/picsfooter.png");
background-repeat: repeat-x, repeat-x;
background-position: top center, bottom center;
padding-bottom: 1.5rem;
padding-left: 1rem;
padding-right: 1rem;
}
h1 {
margin: 0;
padding-top: 1.5rem;
padding-bottom: 1rem;
color:white;
text-align: center;
font-family: 'Teko', sans-serif;
font-size: 3.5rem;
text-shadow: -2px -2px 0 #000,
0 -2px 0 #000,
2px -2px 0 #000,
2px 0 0 #000,
2px 2px 0 #000,
0 2px 0 #000,
-2px 2px 0 #000,
-2px 0 0 #000,
.05em .1em 0 #000;
}
section {
max-width: 960px;
margin: auto;
}
section:not(.shown) {
display: none;
}
nav ul {
display:flex;
justify-content:center;
margin:0;
padding:0;
list-style-type: none;
}
a:not(:hover) {
text-decoration: none;
}
nav a {
color: white!important;
padding: 0.8rem 1.2rem;
display: block;
border-radius: 8px;
text-decoration: none;
margin-left: 0.2rem;
margin-right: 0.2rem;
}
nav a:hover {
background-color:rgba(255,255,255,0.4);
}
nav a.active {
background-color:rgba(255,255,255,0.2);
}
footer {
color: white;
background-color: #343a40;
padding-top: 0.5rem;
padding-left: 1rem;
padding-right: 1rem;
}
footer p {
max-width: 960px;
margin: auto;
padding-bottom: 0.5rem;
}
footer a {
color:#a5d8ff!important;
}
.btn-area {
padding: 1rem;
text-align: center;
}
.btn {
background-color: #e67700;
padding: 0.8rem 1.2rem;
color: white;
font-weight: bold;
text-decoration: none!important;
border-radius: 9999px;
box-shadow: 0px 1px 1px 1px rgba(0, 0, 0, 0.3);
}
.btn:hover {
background-color: #f08c00;
}