bubo-rss/config/template.html
Carter McBride 5f27f8a16e
Update the UI (#10)
* Move the emoji

* Convert to a grid layout

* Ellipsize the feed urls

* Add link to source on GitHub

* Always be updating the relative time of the feed

* Make "recent" within the last 8 hours

* Sort the feeds alphabetically
2024-06-21 16:05:49 -06:00

156 lines
6.4 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<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>Carter's RSS Feeds</title>
<link rel="icon" href="news-emoji.svg" sizes="any" type="image/svg+xml">
<link rel="stylesheet" href="style.css" />
<link rel="manifest" href="manifest.json" />
<script type="module" defer>
/**
* from @feelinglovelynow/get-relative-time
* MIT License
* Copyright (c) 2023 Feeling Lovely Now
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* Simple function that recieves a `Date` object that is in the future or is in the past and gives back the relative time using `Intl.RelativeTimeFormat('en', { numeric: 'auto' })`
* Examples: `[ "last year", "6 months ago", "4 weeks ago", "7 days ago", "now", "in 1 minute", "in 6 hours", "tomorrow", "in 3 days", "in 4 weeks", "next month", "in 2 months", "in 12 months", "next year" ]`
* @param { Date } date
* @throws { { id: 'fln__get-relative-time__invalid-date', message: 'Please pass getRelativeTime() a valid date object', _errorData: { date } } } - `IF (!(date instanceof Date) || date.toString() === 'Invalid Date')`
* @returns { string }
*/
function getRelativeTime(date) {
if (!(date instanceof Date) || date.toString() === 'Invalid Date') throw { id: 'fln__get-relative-time__invalid-date', message: 'Please pass getRelativeTime() a valid date object', _errorData: { date } }
else {
/** @type { string } */
let response
const timestamp = date.getTime()
const rtf = new Intl.RelativeTimeFormat('en', { numeric: 'auto' })
const diffMilliSeconds = timestamp - ((new Date()).getTime())
const diffSeconds = Math.round(diffMilliSeconds / 1000)
const diffMinutes = Math.round(diffSeconds / 60)
const diffHours = Math.round(diffMinutes / 60)
const diffDays = Math.round(diffHours / 24)
if (!Boolean(diffDays) && !Boolean(diffHours) && !Boolean(diffMinutes)) response = rtf.format(diffSeconds, 'second')
else if (!Boolean(diffDays) && !Boolean(diffHours)) response = rtf.format(diffMinutes, 'minute')
else if (!Boolean(diffDays)) response = rtf.format(diffHours, 'hour')
else if (diffDays < -365) response = rtf.format(Math.round(diffDays / 365), 'year')
else if (diffDays < -33) response = rtf.format(Math.round(diffDays / 30), 'month')
else if (diffDays < -7) response = rtf.format(Math.round(diffDays / 7), 'week')
else if (diffDays > 365) response = rtf.format(Math.round(diffDays / 365), 'year')
else if (diffDays > 33) response = rtf.format(Math.round(diffDays / 30), 'month')
else if (diffDays > 7) response = rtf.format(Math.round(diffDays / 7), 'week')
else response = rtf.format(diffDays, 'day')
return response
}
}
/**
* @param { Date } date
* @returns { number }
*/
function getUpdateInterval(date) {
const now = new Date();
const diffMilliSeconds = date.getTime() - now.getTime();
const diffSeconds = Math.round(diffMilliSeconds / 1000);
if (diffSeconds < 60) return 1000;
if (diffSeconds < 3600) return 1000 * 60;
if (diffSeconds < 86400) return 1000 * 60 * 60;
return 1000 * 60 * 60 * 24;
}
class RelativeTime extends HTMLElement {
constructor() {
super();
const date = new Date(parseInt(this.getAttribute("data-time")));
this.textContent = getRelativeTime(date);
setInterval(() => {
requestAnimationFrame(() => {
this.textContent = getRelativeTime(date);
});
}, getUpdateInterval(date));
}
}
customElements.define("relative-time", RelativeTime);
</script>
</head>
<body>
<header>
<h1>📰 Carter's RSS Feeds</h1>
</header>
<main>
{% for group, feeds in data %}
<section>
<h2>{{ group }}</h2>
{% for feed in feeds %}
<details>
<summary>
<span class="feed-title">{{ feed.title }}</span>
<span class="feed-url" title="{{feed.feed}}">({{ feed.feed }})</span>
</summary>
<ul>
{% for item in feed.items %}
<li class="{% if item.isRecent %}has-recent{% endif %}">
<div>
<a class="article-title" href="{{ item.link }}" target="_blank" rel="noopener norefferer nofollow">{{
item.title | safe}}</a>
</div>
<div class="article-timestamp">
<relative-time data-time="{{item.timestamp}}">{{ item.timestamp | relative}}</relative-time>
</div>
</li>
{% endfor %}
</ul>
</details>
{% endfor %}
</section>
{% endfor %}
</main>
{% if errors | length > 0 %}
<h2>Errors</h2>
<p>There were errors trying to parse these feeds:</p>
<ul class="errors">
{% for error in errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
<footer>
<hr>
<p>Last updated {{ now }}.</p>
<p>
<a href="https://github.com/carterworks/rss-reader">View on GitHub</a>
</p>
<p>
Powered by
<a href="https://github.com/georgemandis/bubo-rss">Bubo Reader (v{{ info.version }})</a>, a project by <a
href="https://george.mand.is">George Mandis</a>. ❤️
</p>
</footer>
</body>
</html>