|
1 |
+ |
<!DOCTYPE html> |
|
2 |
+ |
<html lang="en"> |
|
3 |
+ |
<head> |
|
4 |
+ |
<meta charset="UTF-8"> |
|
5 |
+ |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|
6 |
+ |
<title>Blog Feeds</title> |
|
7 |
+ |
<link rel="apple-touch-icon" sizes="180x180" href="https://blogfeeds.net/apple-touch-icon.png"> |
|
8 |
+ |
<link rel="icon" type="image/png" sizes="32x32" href="https://blogfeeds.net/favicon-32x32.png"> |
|
9 |
+ |
<link rel="icon" type="image/png" sizes="16x16" href="https://blogfeeds.net/favicon-16x16.png"> |
|
10 |
+ |
<link rel="manifest" href="https://blogfeeds.net/site.webmanifest"> |
|
11 |
+ |
<link rel="stylesheet" href="tailwindcss" /> |
|
12 |
+ |
<link rel="preconnect" href="https://fonts.googleapis.com"> |
|
13 |
+ |
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> |
|
14 |
+ |
<link href="https://fonts.googleapis.com/css2?family=DM+Sans:ital,opsz,wght@0,9..40,100..1000;1,9..40,100..1000&display=swap" rel="stylesheet"> |
|
15 |
+ |
<meta name="description" content="Creating organic networks through Blogs, RSS, and Feeds"> |
|
16 |
+ |
|
|
17 |
+ |
<!-- Facebook Meta Tags --> |
|
18 |
+ |
<meta property="og:url" content="https://blogfeeds.net"> |
|
19 |
+ |
<meta property="og:type" content="website"> |
|
20 |
+ |
<meta property="og:title" content="Blog Feeds"> |
|
21 |
+ |
<meta property="og:description" content="Creating organic networks through Blogs, RSS, and Feeds"> |
|
22 |
+ |
<meta property="og:image" content="/og.png"> |
|
23 |
+ |
|
|
24 |
+ |
<!-- Twitter Meta Tags --> |
|
25 |
+ |
<meta name="twitter:card" content="summary_large_image"> |
|
26 |
+ |
<meta property="twitter:domain" content="blogfeeds.net"> |
|
27 |
+ |
<meta property="twitter:url" content="https://blogfeeds.net"> |
|
28 |
+ |
<meta name="twitter:title" content="Blog Feeds"> |
|
29 |
+ |
<meta name="twitter:description" content="Creating organic networks through Blogs, RSS, and Feeds"> |
|
30 |
+ |
<meta name="twitter:image" content="/og.png"> |
|
31 |
+ |
<style> |
|
32 |
+ |
* { |
|
33 |
+ |
font-family: 'DM Sans', sans-serif; |
|
34 |
+ |
} |
|
35 |
+ |
details[open] summary svg { |
|
36 |
+ |
transform: rotate(90deg); |
|
37 |
+ |
} |
|
38 |
+ |
</style> |
|
39 |
+ |
</head> |
|
40 |
+ |
<body class="min-h-screen sm:py-0 py-8"> |
|
41 |
+ |
<div class="flex flex-col items-center px-4 pt-12 pb-4"> |
|
42 |
+ |
<div class="max-w-xl space-y-4 w-full"> |
|
43 |
+ |
<a href="/" class="inline-flex items-center text-blue-600 hover:text-blue-800 mb-4 transition-colors"> |
|
44 |
+ |
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"> |
|
45 |
+ |
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7"></path> |
|
46 |
+ |
</svg> |
|
47 |
+ |
Back |
|
48 |
+ |
</a> |
|
49 |
+ |
<img src="/feeds.svg" alt="Feeds" id="feeds" class="w-5/6 mx-auto py-4" /> |
|
50 |
+ |
<p class="text-gray-700 mb-6">To help foster a community around the concept of Blog Feeds, this page acts as an aggregator of thsoe who have a feeds page on their blog. If that's you and you don't see your blog below, then submit the RSS feed below and we'll review it regularly to add it!</p> |
|
51 |
+ |
|
|
52 |
+ |
<form id="feedForm" class="space-y-4"> |
|
53 |
+ |
<div> |
|
54 |
+ |
<label for="url" class="block text-sm font-medium text-gray-700 mb-2">Blog URL</label> |
|
55 |
+ |
<input |
|
56 |
+ |
type="url" |
|
57 |
+ |
id="url" |
|
58 |
+ |
name="url" |
|
59 |
+ |
required |
|
60 |
+ |
placeholder="https://example.com" |
|
61 |
+ |
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 outline-none transition-colors" |
|
62 |
+ |
/> |
|
63 |
+ |
</div> |
|
64 |
+ |
|
|
65 |
+ |
<button |
|
66 |
+ |
type="submit" |
|
67 |
+ |
class="w-full bg-blue-600 hover:bg-blue-700 text-white font-semibold py-2 px-4 rounded-lg transition-colors" |
|
68 |
+ |
> |
|
69 |
+ |
Submit Feed |
|
70 |
+ |
</button> |
|
71 |
+ |
</form> |
|
72 |
+ |
|
|
73 |
+ |
<div id="message" class="hidden my-4 p-4 rounded-lg"></div> |
|
74 |
+ |
</div> |
|
75 |
+ |
</div> |
|
76 |
+ |
|
|
77 |
+ |
<section class="flex flex-col items-center px-4 mb-12"> |
|
78 |
+ |
<div class="max-w-xl space-y-4 w-full"> |
|
79 |
+ |
<div id="feedsList" class="space-y-3"> |
|
80 |
+ |
<div class="text-center py-8 text-gray-500">Loading feeds...</div> |
|
81 |
+ |
</div> |
|
82 |
+ |
</div> |
|
83 |
+ |
</section> |
|
84 |
+ |
|
|
85 |
+ |
<script> |
|
86 |
+ |
// Load feeds on page load |
|
87 |
+ |
async function loadFeeds() { |
|
88 |
+ |
const feedsList = document.getElementById('feedsList'); |
|
89 |
+ |
|
|
90 |
+ |
try { |
|
91 |
+ |
const response = await fetch('https://api.blogfeeds.net'); |
|
92 |
+ |
const data = await response.json(); |
|
93 |
+ |
|
|
94 |
+ |
if (data.subscriptions && data.subscriptions.length > 0) { |
|
95 |
+ |
feedsList.innerHTML = data.subscriptions.map(feed => { |
|
96 |
+ |
const blogUrl = new URL(feed.htmlUrl); |
|
97 |
+ |
const rootUrl = `${blogUrl.protocol}//${blogUrl.host}`; |
|
98 |
+ |
|
|
99 |
+ |
return ` |
|
100 |
+ |
<div class="p-4 border border-gray-200 rounded-lg hover:bg-gray-50 transition-colors"> |
|
101 |
+ |
<h3 class="font-semibold text-lg mb-1"> |
|
102 |
+ |
<a href="${rootUrl}" target="_blank" class="hover:text-blue-600 transition-colors">${feed.title}</a> |
|
103 |
+ |
</h3> |
|
104 |
+ |
<a href="${feed.url}" target="_blank" class="text-sm text-gray-600 hover:text-blue-600 transition-colors break-all inline-flex items-center gap-2"> |
|
105 |
+ |
<svg class="w-3 h-3 flex-shrink-0" fill="currentColor" viewBox="0 0 24 24"> |
|
106 |
+ |
<path d="M6.503 20.752c0 1.794-1.456 3.248-3.251 3.248-1.796 0-3.252-1.454-3.252-3.248 0-1.794 1.456-3.248 3.252-3.248 1.795.001 3.251 1.454 3.251 3.248zm-6.503-12.572v4.811c6.05.062 10.96 4.966 11.022 11.009h4.817c-.062-8.71-7.118-15.758-15.839-15.82zm0-3.368c10.58.046 19.152 8.594 19.183 19.188h4.817c-.03-13.231-10.755-23.954-24-24v4.812z"/> |
|
107 |
+ |
</svg> |
|
108 |
+ |
${feed.url} |
|
109 |
+ |
</a> |
|
110 |
+ |
</div> |
|
111 |
+ |
`; |
|
112 |
+ |
}).join(''); |
|
113 |
+ |
} else { |
|
114 |
+ |
feedsList.innerHTML = '<div class="text-center py-8 text-gray-500">No feeds available yet.</div>'; |
|
115 |
+ |
} |
|
116 |
+ |
} catch (error) { |
|
117 |
+ |
feedsList.innerHTML = '<div class="text-center py-8 text-red-600">Failed to load feeds. Please try again later.</div>'; |
|
118 |
+ |
} |
|
119 |
+ |
} |
|
120 |
+ |
|
|
121 |
+ |
// Load feeds when page loads |
|
122 |
+ |
loadFeeds(); |
|
123 |
+ |
|
|
124 |
+ |
document.getElementById('feedForm').addEventListener('submit', async (e) => { |
|
125 |
+ |
e.preventDefault(); |
|
126 |
+ |
|
|
127 |
+ |
const url = document.getElementById('url').value; |
|
128 |
+ |
const messageDiv = document.getElementById('message'); |
|
129 |
+ |
const submitBtn = e.target.querySelector('button[type="submit"]'); |
|
130 |
+ |
|
|
131 |
+ |
// Show loading state |
|
132 |
+ |
submitBtn.disabled = true; |
|
133 |
+ |
submitBtn.textContent = 'Submitting...'; |
|
134 |
+ |
messageDiv.classList.add('hidden'); |
|
135 |
+ |
|
|
136 |
+ |
try { |
|
137 |
+ |
const response = await fetch('https://api.blogfeeds.net/add-feed', { |
|
138 |
+ |
method: 'POST', |
|
139 |
+ |
headers: { |
|
140 |
+ |
'Content-Type': 'application/json', |
|
141 |
+ |
}, |
|
142 |
+ |
body: JSON.stringify({ url }) |
|
143 |
+ |
}); |
|
144 |
+ |
|
|
145 |
+ |
const data = await response.json(); |
|
146 |
+ |
|
|
147 |
+ |
if (response.ok) { |
|
148 |
+ |
messageDiv.className = 'mt-4 p-4 rounded-lg bg-green-100 text-green-800'; |
|
149 |
+ |
messageDiv.textContent = 'Feed submitted successfully!'; |
|
150 |
+ |
document.getElementById('url').value = ''; |
|
151 |
+ |
} else { |
|
152 |
+ |
messageDiv.className = 'mt-4 p-4 rounded-lg bg-red-100 text-red-800'; |
|
153 |
+ |
messageDiv.textContent = data.error || 'Failed to submit feed. Please try again.'; |
|
154 |
+ |
} |
|
155 |
+ |
} catch (error) { |
|
156 |
+ |
messageDiv.className = 'mt-4 p-4 rounded-lg bg-red-100 text-red-800'; |
|
157 |
+ |
messageDiv.textContent = 'Network error. Please try again.'; |
|
158 |
+ |
} finally { |
|
159 |
+ |
submitBtn.disabled = false; |
|
160 |
+ |
submitBtn.textContent = 'Submit Feed'; |
|
161 |
+ |
messageDiv.classList.remove('hidden'); |
|
162 |
+ |
} |
|
163 |
+ |
}); |
|
164 |
+ |
</script> |
|
165 |
+ |
</body> |
|
166 |
+ |
</html> |