Initial implementation
This commit is contained in:
commit
051c9f76f5
21
LICENSE
Normal file
21
LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2023 Alex Thomassen <alex@thomassen.sh>
|
||||
|
||||
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.
|
15
blog.html
Normal file
15
blog.html
Normal file
@ -0,0 +1,15 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
</head>
|
||||
<body class="bg-slate-800 text-white py-6 px-8">
|
||||
<h1 class="text-3xl font-bold underline">Blog</h1>
|
||||
<div id="blog-posts"></div>
|
||||
|
||||
<button id="view-more" class="hidden bg-orange-500 hover:bg-orange-700 text-white font-bold py-2 px-4 rounded">View More</button>
|
||||
</body>
|
||||
<script src="/blog.js"></script>
|
||||
</html>
|
140
blog.js
Normal file
140
blog.js
Normal file
@ -0,0 +1,140 @@
|
||||
/**
|
||||
* The base URI for the WordPress API. Don't forget `http(s)://`!
|
||||
* Depending on where your WordPress blog is hosted, this could be something like: `https://example.wordpress.com`
|
||||
*
|
||||
* @type {String}
|
||||
*/
|
||||
const wordPressBaseUri = 'https://wptest.decicus.com';
|
||||
|
||||
/**
|
||||
* Fetches 10 posts from WordPress API.
|
||||
* Uses: https://developer.wordpress.org/rest-api/reference/posts/#list-posts
|
||||
*
|
||||
* @param {Number} page Which page to fetch, by default the first page (1)
|
||||
* @param {Number} perPage How many posts to fetch per page, by default 10
|
||||
* @returns {Array}
|
||||
*/
|
||||
async function fetchPosts(page = 1, perPage = 10)
|
||||
{
|
||||
const response = await fetch(`${wordPressBaseUri}/wp-json/wp/v2/posts?page=${page}&per_page=${perPage}`);
|
||||
const json = await response.json();
|
||||
return json;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used for tracking what "page" from the WordPress API we should be fetching.
|
||||
* You should generally not change this value.
|
||||
*/
|
||||
let nextPage = 1;
|
||||
|
||||
/**
|
||||
* Can be used for tweaking how many posts to get per page.
|
||||
* Will also affect how many times you have to click "View more" to get all posts
|
||||
*/
|
||||
const perPage = 10;
|
||||
|
||||
const viewMoreButton = document.querySelector('#view-more');
|
||||
async function getPosts()
|
||||
{
|
||||
// Disable the "View More" button while we're fetching posts, to avoid people spamming the button
|
||||
viewMoreButton.setAttribute('disabled', '1');
|
||||
|
||||
// Get the first set of posts from the API
|
||||
const posts = await fetchPosts(nextPage, perPage);
|
||||
|
||||
// Get the container where we want to put the posts. By default this can just be an empty div.
|
||||
const postsContainer = document.querySelector('#blog-posts');
|
||||
|
||||
/**
|
||||
* Style points only
|
||||
*/
|
||||
let firstPostId = null;
|
||||
|
||||
// Loop though the posts and create the HTML elements for each post
|
||||
for (const post of posts)
|
||||
{
|
||||
/**
|
||||
* Style points only
|
||||
*
|
||||
* Since `firstPostId` is still `null`, we set it to the post's ID.
|
||||
* Any further posts in this batch will *not* override it.
|
||||
* Meaning it will in fact be "the first post" (of this batch).
|
||||
*/
|
||||
if (firstPostId === null)
|
||||
{
|
||||
firstPostId = post.id;
|
||||
}
|
||||
|
||||
// Create post's parent div
|
||||
const postElement = document.createElement('div');
|
||||
postElement.setAttribute('data-post-id', post.id);
|
||||
postElement.classList.add('post');
|
||||
|
||||
// Purely for styling, can ignore this part
|
||||
postElement.classList.add('bg-rose-900');
|
||||
postElement.classList.add('p-4');
|
||||
postElement.classList.add('my-4');
|
||||
|
||||
// Create post's title as a h2
|
||||
const postTitle = document.createElement('h2');
|
||||
postTitle.textContent = post.title.rendered;
|
||||
|
||||
// Purely for styling, can ignore this part
|
||||
postTitle.classList.add('text-xl');
|
||||
postTitle.classList.add('font-bold');
|
||||
postTitle.classList.add('mb-2');
|
||||
|
||||
// Create post's content. This is a div because WordPress will give you a lot of HTML tags in the content (e.g. `p`).
|
||||
const postContent = document.createElement('div');
|
||||
postContent.innerHTML = post.content.rendered;
|
||||
|
||||
// Append the title and content to the post's parent div
|
||||
postElement.appendChild(postTitle);
|
||||
postElement.appendChild(postContent);
|
||||
|
||||
// Append the post's parent div to the container
|
||||
postsContainer.appendChild(postElement);
|
||||
}
|
||||
|
||||
/**
|
||||
* Style points only
|
||||
* Only trigger this logic after the "view more" button has been pressed
|
||||
*/
|
||||
if (nextPage > 1) {
|
||||
/**
|
||||
* Style points only
|
||||
* Scroll to the first post we got from the API.
|
||||
* This will scroll to the first post of the current batch of posts
|
||||
*/
|
||||
const firstPost = document.querySelector(`[data-post-id="${firstPostId}"]`);
|
||||
firstPost.scrollIntoView({ behavior: 'smooth' });
|
||||
}
|
||||
|
||||
/**
|
||||
* If the amount of posts we got from the API is less than the amount of posts we requested,
|
||||
* then we know that we have reached the end of the posts and we can hide the "View More" button.
|
||||
*/
|
||||
const viewMoreClasses = viewMoreButton.classList;
|
||||
if (posts.length >= perPage)
|
||||
{
|
||||
viewMoreClasses.remove('hidden');
|
||||
|
||||
// Increase `nextPage` by 1 so that the next time we fetch posts, we get the next page
|
||||
nextPage++;
|
||||
}
|
||||
/**
|
||||
* If the amount of posts we got from the API is less than the amount of posts we requested,
|
||||
* then we know that we have reached the end of the posts and we can hide the "View More" button.
|
||||
*/
|
||||
else {
|
||||
viewMoreClasses.add('hidden');
|
||||
}
|
||||
|
||||
// Re-enable the "View More" button
|
||||
viewMoreButton.removeAttribute('disabled');
|
||||
}
|
||||
|
||||
// Add an event listener to the "View More" button so that we can fetch more posts when it's clicked
|
||||
viewMoreButton.addEventListener('click', getPosts);
|
||||
|
||||
getPosts();
|
12
index.html
Normal file
12
index.html
Normal file
@ -0,0 +1,12 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
</head>
|
||||
<body class="bg-slate-800 text-white py-6 px-8">
|
||||
<h1 class="text-3xl font-bold underline">Hello, world!</h1>
|
||||
<p>Visit the <a href="/blog.html" class="text-orange-300">blog</a>!</p>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in New Issue
Block a user