Skip to content

Commit

Permalink
Feat/add docs page (#3)
Browse files Browse the repository at this point in the history
* add json-based feed & post embedding

* feat(docs): prep for docs site

* feat(docs): add deploy action, update package.json

* feat(docs): add docs dir

* feat(docs): move to simple deployment

* feat(docs): fix script url

* feat(docs): rebuild/deploy

* feat(docs): update page
  • Loading branch information
andy-blum authored Jul 24, 2023
1 parent 18a6d1d commit 7d1af5f
Show file tree
Hide file tree
Showing 10 changed files with 1,843 additions and 70 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
/node_modules
.parcel-cache
test
126 changes: 94 additions & 32 deletions dist/fed-embed.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,23 @@
class FedEmbed extends HTMLElement {
feedUrl;
timeout;
user;
post;
constructor() {
super();
const { source, timeout } = this.dataset;
const { source, timeout, user, post } = this.dataset;
try {
this.feedUrl = new URL(source);
}
catch (error) {
console.error(error);
console.error('A fed-embed element did not have a valid source URL and has self-destructed.');
this.remove();
return;
catch (_error) { }
try {
this.user = new URL(user);
}
catch (_error) { }
try {
this.post = new URL(post);
}
catch (_error) { }
this.timeout = Number(timeout) || 600;
const sheet = new CSSStyleSheet();
sheet.replaceSync(`
Expand All @@ -31,48 +38,103 @@ class FedEmbed extends HTMLElement {
`);
document.adoptedStyleSheets = [sheet];
}
async connectedCallback() {
const feed = await this.getFeed();
connectedCallback() {
switch (true) {
case (!!this.feedUrl):
this.renderRSSFeed();
break;
case (!!this.user):
this.renderJSONFeed();
break;
case (!!this.post):
this.renderPost();
break;
default:
console.error(`No valid URLs found on ${this.outerHTML}`);
this.selfDestruct();
break;
}
}
async renderRSSFeed() {
const feedString = await this.fetch(this.feedUrl);
const feed = this.parseXML(feedString);
const postsList = document.createElement('ul');
feed.querySelectorAll('item').forEach(item => {
const text = item.querySelector('description').textContent;
postsList.insertAdjacentHTML('beforeend', `<li>${text}</li>`);
});
this.append(postsList);
}
async getFeed() {
const { feedUrl } = this;
let cachedFeed = false;
async renderJSONFeed() {
const { origin, pathname } = this.user;
let accountLookupURL, statusesURL;
try {
cachedFeed = localStorage.getItem(feedUrl.toString()) || false;
accountLookupURL = new URL(`${origin}/api/v1/accounts/lookup?acct=${pathname.replaceAll(/\/@/g, '')}`);
}
catch (_error) { }
catch (error) {
this.selfDestruct(error);
return;
}
const { error, id } = JSON.parse(await this.fetch(accountLookupURL));
if (error) {
this.selfDestruct(error);
return;
}
try {
statusesURL = new URL(`${origin}/api/v1/accounts/${id}/statuses?exclude_replies=true&exclude_reblogs=true`);
}
catch (error) {
this.selfDestruct(error);
return;
}
const posts = JSON.parse(await this.fetch(statusesURL));
const postsList = document.createElement('ul');
posts.forEach((post) => {
postsList.insertAdjacentHTML('beforeend', `<li>${post.content}</li>`);
});
this.append(postsList);
}
async renderPost() {
const { origin, pathname } = this.post;
let postURL;
try {
postURL = new URL(`${origin}/api/v1/statuses/${pathname.split('/').at(-1)}`);
}
catch (error) {
this.selfDestruct(error);
return;
}
const { error, content } = JSON.parse(await this.fetch(postURL));
if (error) {
this.selfDestruct(error);
return;
}
this.insertAdjacentHTML('beforeend', content);
}
selfDestruct(error = null) {
if (error) {
console.error(error);
}
console.error('A <fed-embed> element has self destructed. Additional logging information may be available above.');
this.remove();
}
async fetch(sourceURL) {
const { timeout } = this;
const cachedFeed = localStorage.getItem(sourceURL.toString()) || false;
if (cachedFeed) {
const { expires, feedString: cachedString } = JSON.parse(cachedFeed);
if (expires < Date.now()) {
localStorage.removeItem(feedUrl.toString());
const feedText = await this.fetchRss();
return this.parseXML(feedText);
}
else {
return this.parseXML(cachedString);
const { expires, dataAsString } = JSON.parse(cachedFeed);
if (expires > Date.now()) {
return dataAsString;
}
localStorage.removeItem(sourceURL.toString());
}
const feedText = await this.fetchRss();
return this.parseXML(feedText);
}
async fetchRss() {
const { feedUrl, timeout } = this;
const request = await fetch(feedUrl);
const request = await fetch(sourceURL.toString());
const response = await request.text();
const cacheItem = {
expires: Date.now() + (timeout * 1000),
feedString: response,
dataAsString: response,
};
try {
localStorage.setItem(feedUrl.toString(), JSON.stringify(cacheItem));
}
catch (_error) { }
localStorage.setItem(sourceURL.toString(), JSON.stringify(cacheItem));
return response;
}
parseXML(xmlString) {
Expand Down
2 changes: 1 addition & 1 deletion dist/fed-embed.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions docs/index.08d28b45.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions docs/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Embed The Fed</title><link rel="stylesheet" href="https://unpkg.com/mvp.css"><style>details{border:1px solid #000;padding:1rem}fed-embed:where(:defined):where(:not(.styled)){background:#0000000d;margin-top:1rem;padding:0 1rem}</style></head><body> <main> <h1>Embed The Fed</h1> <p>All it takes is a single javascript file & one new element in your markup to embed any fediverse feed you want!</p> <code>&lt;script src="https://cdn.jsdelivr.net/gh/andy-blum/fed-embed/dist/fed-embed.min.js"&gt;&lt;script&gt;</code> <hr> <h2>Get all posts by a user</h2> <code>&lt;fed-embed data-user="https://mastodon.social/@mastodon"&gt;&lt;/fed-embed&gt;</code> <details> <summary>Demo</summary> <fed-embed data-user="https://mastodon.social/@mastodon"></fed-embed> </details> <hr> <h2>Get a single post</h2> <code>&lt;fed-embed data-post="https://mastodon.social/@Mastodon/5258563"&gt;&lt;/fed-embed&gt;</code> <details> <summary>Demo</summary> <fed-embed data-post="https://mastodon.social/@Mastodon/5258563"></fed-embed> </details> <hr> <h2>Style it however you want</h2> <code style="white-space:break-spaces"> fed-embed.styled { border: 10px dashed orange; background: darkviolet; color: white; text-transform: uppercase; font-weight: bolder; } &lt;fed-embed class="styled" data-post="https://mastodon.social/@Mastodon/5258563"&gt;&lt;/fed-embed&gt; </code> <details> <summary>Demo</summary> <style>fed-embed.styled{color:#fff;text-transform:uppercase;background:#9400d3;border:10px dashed orange;font-weight:bolder}</style> <fed-embed class="styled" data-post="https://mastodon.social/@Mastodon/5258563"></fed-embed> </details> </main> <script src="index.08d28b45.js"></script> </body></html>
79 changes: 79 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Embed The Fed</title>
<link rel="stylesheet" href="https://unpkg.com/mvp.css">
<style>
details {
border: 1px solid black;
padding: 1rem;
}

fed-embed:where(:defined):where(:not(.styled)) {
padding: 0 1rem;
margin-top: 1rem;
background: rgba(0,0,0,0.05);
}
</style>
</head>
<body>
<main>
<h1>Embed The Fed</h1>
<p>All it takes is a single javascript file & one new element in your markup to embed any fediverse feed you want!</p>
<code>&lt;script src="https://cdn.jsdelivr.net/gh/andy-blum/fed-embed/dist/fed-embed.min.js"&gt;&lt;script&gt;</code>

<hr>
<h2>Get all posts by a user</h2>
<code>&lt;fed-embed data-user="https://mastodon.social/@mastodon"&gt;&lt;/fed-embed&gt;</code>

<details>
<summary>Demo</summary>
<fed-embed data-user="https://mastodon.social/@mastodon"></fed-embed>
</details>

<hr>

<h2>Get a single post</h2>

<code>&lt;fed-embed data-post="https://mastodon.social/@Mastodon/5258563"&gt;&lt;/fed-embed&gt;</code>

<details>
<summary>Demo</summary>
<fed-embed data-post="https://mastodon.social/@Mastodon/5258563"></fed-embed>
</details>

<hr>

<h2>Style it however you want</h2>

<code style="white-space:break-spaces;">
fed-embed.styled {
border: 10px dashed orange;
background: darkviolet;
color: white;
text-transform: uppercase;
font-weight: bolder;
}

&lt;fed-embed class="styled" data-post="https://mastodon.social/@Mastodon/5258563"&gt;&lt;/fed-embed&gt;
</code>

<details>
<summary>Demo</summary>
<style>
fed-embed.styled {
border: 10px dashed orange;
background: darkviolet;
color: white;
text-transform: uppercase;
font-weight: bolder;
}
</style>
<fed-embed class="styled" data-post="https://mastodon.social/@Mastodon/5258563"></fed-embed>
</details>
</main>
<script src="./dist/fed-embed.min.js"></script>
</body>
</html>
8 changes: 5 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
{
"name": "rss-feed",
"name": "fed-embed",
"version": "1.0.0",
"description": "A standalone web component you can use to embed an RSS feed on a webpage.",
"main": "index.js",
"license": "MIT",
"devDependencies": {
"jsmin": "^1.0.1",
"parcel": "^2.9.3",
"typescript": "^5.1.6"
},
"scripts": {
"start": "yarn tsc && node build.mjs"
"build": "yarn tsc && node build.mjs",
"dev": "parcel index.html --dist-dir './test' --no-source-maps",
"deploy": "parcel build index.html --dist-dir './docs' --no-source-maps --public-url ./"
}
}
Loading

0 comments on commit 7d1af5f

Please sign in to comment.