Hello, this is my first post!
[tag] hello world, first post
Taking the time to inform everyone that Rise of the Teenage Mutant Ninja Turtles exists. That is all
[tag] rottmnt
[sign]
Look at this thing! I made it in a number of days and it brings me joy!
More seriously, this a script for individuals who want a blog but don't want to go through the hassle of updating it, either through some third party or (more annoyingly) by hand. Oh, the horror of website making (affectionate).
Basically, it takes in a page that looks like this:
<script defer src=do_blog.js></script>
<div id=blog></div>
<div id=blog-archive hidden>
# Hello, this is my first post!
2024-12-16
[tag] hello world, first post
Taking the time to inform everyone that Rise of the Teenage Mutant Ninja Turtles exists. That is all
[tag] rottmnt
[sign]
</div>
And turns it into this:
[tag] hello world, first post
Taking the time to inform everyone that Rise of the Teenage Mutant Ninja Turtles exists. That is all
[tag] rottmnt
[sign]
For transparency's sake, I'm leaving this example here to show the result with a single post.
It doesn't look like much, but it's functional and much nicer when it has its own webpage and CSS. And, of course, you can build more webpage around the blog. Sort of like I built this page around the example.
The script, however, does assume that the page's main content is the blog, so it changes the title
to the blog's title, which is why this page is titled Blog instead of do_blog.js.
I tried to make it as customizable as I could, so if you want to see how well it really works out as a blogging tool, check out this example blog or my blog!
The rest of this page functions as documentation for its usage and customization.
EDIT: Due to popular demand (from myself, I demanded it), I've made a stylesheet for the souls who have no more CSSing in them for the day (or their life). Understandable.
To see how the CSS looks, check out the Example Blog I made.
Download:
Or copy the code below:
Put the script at the end of your body
or in your head
with the defer
attribute. The only set up you need is the script and two divs.
<script src="do_blog.js" defer></script>
<div id=blog></div>
<div id=blog-archive hidden></div>
The only div
you actually need to touch is the #blog-archive
. Skip lines whenever you want to make a new paragraph, a new post, or use a command.
The basic format of a blog post:
# Blog Title date time The rest of the post
The # and date time are mandatory!
The # indicates a new blog post.
Date time can be in date time string format (YYYY-MM-DDTHH:mm:ss.sssZ) or in milliseconds since the epoch. For example, it is Monday, December 16, 2024 13:47 for me.
new Date().toISOString()
new Date().getTime()
I have provided two commands.
The commands may be used as many times per post as you want.
Finally, there are quite a few things to customize, though there is no real need to if one doesn't want to.
All you need to do is make an object named MY_BLOG
in a script
that loads before do_blog.js. The following example displays all the customizable options and their defaults.
<script>
MY_BLOG = {
// blogging experience
new_post: '#',
tag_cmd: '[tag]',
sign_cmd: '[sign]',
title: 'Blog',
no_posts_msg: 'This person has not posted yet! Come back later :3',
none_tagged_msg: 'There are no posts under this tag!',
// blog post
title_is_link: true,
link_text: '[link]', // if title is not link
tags_in_footer: false,
cut_long_posts: .75 * window.innerHeight,
img_height: 300,
read_more: 'Read more',
replacers: [],
newTitle: (post) => { // when post has no title
const temp = document.createElement('div');
DO_BLOG.replacers.forEach ( e => {
const arr = post.body.split(e[0]);
temp.innerHTML = arr.join(e[1]);
});
const arr = temp.textContent.slice(0,20).split(/\s+/);
arr.pop();
return arr.join(' ') + '…';
},
getDate: (date) => {
return date.toUTCString().slice(0,16);
},
signature: (post) => {
return 'Posted ' + post.date.toLocaleDateString();
},
// nav
links_heading: 'Links',
skip_to_content: 'Skip to content',
open_navs: 2,
months: [
'January',
'February',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December'
],
navTitle: (post) => {
return post.date.toLocaleDateString();
},
// tag form
tag_label: 'Tag: ',
all_tags: '--All tags--',
tag_search: 'Go',
// sort form
sort_old_to_new: 'Sort old to new',
sort_new_to_old: 'Sort new to old',
// search pages nav
load_limit: 10,
pagination_limit: 6,
skip_pagination: 'Skip pagination',
previous_page: 'Prev',
page_label: 'Page: ',
next_page: 'Next',
// breadcrumb nav
breadcrumb_trail: '/',
breadcrumb_article: 'Article',
breadcrumb_tag: 'Tag',
// article nav
next_post: '← Next',
post_nav_separator: ' | ',
previous_post: 'Prev →',
// aria-label (for pagination and tags)
aria_goto_page: 'Goto page ',
aria_current_page: 'Current page, page ',
aria_page_of: ['Page ', ' of '],
aria_pagination: 'Pagination',
aria_breadcrumbs: 'Breadcrumbs',
aria_tags: 'Tags',
do_onload: (posts) => {},
}
</script>
Let's go over the details of each option
new_post: '#'
RegExp
(regex), so some characters may need to be escaped with a double backslash (\\).
tag_cmd: '[tag]'
sign_cmd: '[sign]'
signature
containing your signature, which you can change in the signature
property.
title: 'Blog'
title
element's text will also be set to this.
no_posts_msg: 'This person has not posted yet! Come back later :3'
#blog-archive
is empty or does not exist.
none_tagged_msg: 'There are no posts under this tag!'
title_is_link: true
false
, then a separate link will be created in the header.
link_text: '[link]'
tags_in_footer: false
cut_long_posts: .75 * window.innerHeight
img_height: 300
show_more: 'Show more'
replacers: []
replacers
' first element and then joined back together with the second.
['foo','bar']
:
'This foo is a bar foo bar of bar.'
['This ', ' is a bar ', ' bar of bar.']
'This bar is a bar bar bar of bar.'
newTitle: (post) => {
...
},
post
argument is a Post object, which has the following properties and methods:
getDate: (date) => {
return date.toUTCString().slice(0,16);
}
signature: (post) => {
return 'Posted ' + post.date.toLocaleDateString();
}
post
argument is an object with the following properties:
links_heading: 'Links'
skip_to_content: 'Skip to content'
open_navs: 2
details
elements to open in the navigation. These are opened in order, so the details
opened will be the first year to appear in the nav
, and then the months in that year, then the second year, and so on.
months: [
'January',
'February',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December'
]
navTitle: (post) => {
return post.date.toLocaleDateString();
}
post
argument is a Post object, so one may choose to use the post.title
or follow the default's example and use post.date
to change how the blog post's link appears.
tag_label: 'Tag: '
all_tags: '--All tags--'
tag_search: 'Go'
sort_old_to_new: 'Sort old to new'
sort_new_to_old: 'Sort new to old'
load_limit: 10
pagination_limit: 6
select
element with previous and next links.
skip_pagination: 'Skip pagination'
previous_page: 'Prev'
page_label: 'Page: '
next_page: 'Next'
breadcrumb_trail: '/'
breadcrumb_article: 'Article'
breadcrumb_tag: 'Tag'
next_post: '← Next'
post_nav_separator: ' | '
previous_post: 'Prev →'
aria_goto_page: 'Goto page '
aria_current_page: 'Current page, page '
aria_page_of: ['Page ', ' of ']
aria_pagination: 'Pagination'
aria_breadcrumbs: 'Breadcrumbs'
aria_tags: 'Tags'
aria-label
attribute, the pagination nav and links should read:
do_onload: (posts) => {}
posts
argument is an Array of all the Post objects (every blog post). Perhaps you want to pin a post? Then you can search for that post by id, date, title, or tag, and use the Post.getArticle
method to append it wherever your pinned posts go. For example:
do_onload: posts => {
const pinned = posts.filter( p => {
return p.tags.indexOf('pin') > -1
});
const firstSection = document.querySelector('#blog-content .section');
pinned.forEach( p => {
firstSection.parentElement.insertBefore(p, firstSection);
});
}
Here's the general format do_blog should result in. I've included, hopefully, an example of everything, so just know that before wondering why there are two page navs or why there are tags in the header and the footer.
#blog.blog
div.blog-bar
nav#blog-nav
h2.links "Links"
a.skip-to-content "Skip to content"
details.year
summary "2000"
ul.months
li
details.month
summary "January"
ul.posts
li
a "1/1/2000"
hr
form#tag-form
label#tag-search "Tag: "
select
button "Go"
form#sort-form
button "Sort old to new"
div#blog-content.blog-main
nav.breadcrumbs
a.breadcrumb "Blog"
span.trail "/"
span.breadcrumb "Tag"
span.trail "/"
a.current.breadcrumb "hashtag"
nav.top.pagination.link-navigation
a.skip-to-content "Skip pagination"
a.current "1"
a "2"
hr
nav.top.pagination.select-navigation
a.skip-to-content "Skip pagination"
a.previous-page "Prev"
label "Page: "
select
a.next-page "Next"
hr
h2.year.section "2000"
h3.month.section "January"
article.post.cut-off
header.header
h1.title
a "Blog Title"
p.date
time "Sat, 01 Jan 2000"
a.blog-link "[link]"
ul.tags
li.tag
a "hashtag"
div.body.cut-off
p "This is a cut off blog post paragraph"
button.show-more "Show more"
footer
ul.tags
li.tag
a "hashtag"
nav.bottom.pagination.link-navigation
hr
a.current "1"
a "2"
nav.bottom.pagination.page-navigation
hr
a.previous-page "Prev"
label "Page: "
select
a.next-page "Next"
#blog.article
nav.breadcrumbs
a.breadcrumb "Blog"
span.trail "/"
span.breadcrumb "Article"
span.trail "/"
a.current.breadcrumb "Blog Title"
nav.top.post-navigation
a.next-post "← Next"
span.separator " | "
a.previous-post "Prev →"
article.post
header.header
h1.title "Blog Title"
p.date
time "Sat, 01 Jan 2000"
ul.tags
li.tag
a "hashtag"
div.body
p "This is a full blog post paragraph"
footer
ul.tags
li.tag
a "hashtag"
nav.bottom.post-navigation
a.next-post "← Next"
span.separator " | "
a.previous-post "Prev →"