From f554a4c6a2c086f9a3ca7d459590303df7cc38fc Mon Sep 17 00:00:00 2001 From: Monty Date: Sat, 18 Sep 2021 18:25:28 +0200 Subject: [PATCH] [blog]: Add syntax highlighting, styling for all elements, mobile support --- blogposts/test.md | 137 ++++++++++++++++++++++++ blogposts/todo.md | 15 ++- locales/US_en.json | 3 +- public/assets/css/blog.css | 103 +++++++++++------- public/assets/css/blogpost.css | 172 ++++++++++++++++++++++++------ public/assets/css/highlightjs.css | 91 ++++++++++++++++ public/assets/css/main.css | 6 +- public/assets/images/check.svg | 1 + src/routers/blog.js | 2 + views/blog.handlebars | 11 +- views/blogpost.handlebars | 7 +- views/partials/header.handlebars | 1 + 12 files changed, 458 insertions(+), 91 deletions(-) create mode 100644 blogposts/test.md create mode 100644 public/assets/css/highlightjs.css create mode 100644 public/assets/images/check.svg diff --git a/blogposts/test.md b/blogposts/test.md new file mode 100644 index 0000000..d6267c5 --- /dev/null +++ b/blogposts/test.md @@ -0,0 +1,137 @@ +--- +title: "Test" +author: "Monty" +author_image: "https://www.github.com/montylion.png" +date: "January 20, 2038" +caption: "A post to test the styling of the various elements we might use (rename to _test.md before deploying the blog section)" +cover_image: "https://media.discordapp.net/attachments/413884110667251722/886474243662037062/image1.jpg" +--- + +A post to test the styling of the various elements we might use (rename to _test.md before deploying the blog section) + +**bold** + +[**bold url**](https://www.youtube.com/watch?v=HGoCNOFpWpo) + +_italic_ + +[_italic url_](https://www.youtube.com/watch?v=HGoCNOFpWpo) + +~strikethrough~ + +[~strikethrough url~](https://www.youtube.com/watch?v=HGoCNOFpWpo) + +# h1 + +## h2 + +### h3 + +#### h4 + +##### h5 + +###### h6 + +--- + +| Element | Description | +| :----------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| table | The table HTML element represents tabular data — that is, information presented in a two-dimensional table comprised of rows and columns of cells containing data. | +| tuble | The tuble HTML element represents tubular data — that is, information presented in a totally gnarly and radical way. | +| table | A table is an item of furniture with a flat top and one or more legs, used as a surface for working at, eating from or on which to place things. | + +| Element | Description | +| ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| table | The table HTML element represents tabular data — that is, information presented in a two-dimensional table comprised of rows and columns of cells containing data. | +| tuble | The tuble HTML element represents tubular data — that is, information presented in a totally gnarly and radical way. | +| table | A table is an item of furniture with a flat top and one or more legs, used as a surface for working at, eating from or on which to place things. | + +| Element | Description | +| -----------: | -----------------------------------------------------------------------------------------------------------------------------------------------------------------: | +| table | The table HTML element represents tabular data — that is, information presented in a two-dimensional table comprised of rows and columns of cells containing data. | +| tuble | The tuble HTML element represents tubular data — that is, information presented in a totally gnarly and radical way. | +| table | A table is an item of furniture with a flat top and one or more legs, used as a surface for working at, eating from or on which to place things. | + +Yee haw 🤠 + +- list +- list + - list + - list + - list + +69. list +1. list + 1. list + 1. list + 1. list + +- [ ] Unchecked checkbox +- [x] Checked checkbox + +```js +class trueOrFalseObject { + constructor(trueOrFalse) { + this.trueOrFalse = trueOrFalse; + } + get trueOrFalse() { + return this.trueOrFalse(); + } + trueOrFalse() { + return this.trueOrFalse; + } +} + +let objectWhichWeKnowIsTrue = new trueOrFalseObject(true); + +function checkIfTrueOrFalse(objectToCheckIfTrueOrFalse) { + if (objectToCheckIfTrueOrFalse === objectWhichWeKnowIsTrue.trueOrFalse) { + return objectWhichWeKnowIsTrue.trueOrFalse; + console.log( + "Successfully checked if the object is true or false. Result: the object is true." + ); + // For whatever reason this doesn't log, can't figure out why /s + } else { + objectWhichWeKnowIsTrue = new trueOrFalseObject(false); + if (objectToCheckIfTrueOrFalse === objectWhichWeKnowIsTrue.trueOrFalse) { + return objectWhichWeKnowIsTrue.trueOrFalse; + console.log( + "Successfully checked if the object is true or false. Result: the object is false." + ); + // For whatever reason this doesn't log either, will probably ask on StackOverflow or something /s + } else { + // something went horribly wrong + } + objectWhichWeKnowIsTrue = new trueOrFalseObject(true); + } +} + +const isTrueTrueOrFalse = checkIfTrueOrFalse(true); +const isfalseTrueOrFalse = checkIfTrueOrFalse(false); + +const trueOrFalseJSON = { + true: isTrueTrueOrFalse, + false: isfalseTrueOrFalse, +}; + +console.log(trueOrFalseJSON); + +// Ok but seriously don't run this for the love of god I feel sorry for writing this even as a joke +``` + +> The blockquote HTML element indicates that the enclosed text is an extended quotation. Usually, this is rendered visually by indentation. A URL for the source of the quotation may be given using the cite attribute, while a text representation of the source can be given using the cite element. +> > The blockquote HTML element indicates that the enclosed text is an extended quotation. Usually, this is rendered visually by indentation. A URL for the source of the quotation may be given using the cite attribute, while a text representation of the source can be given using the cite element. +> > > The blockquote HTML element indicates that the enclosed text is an extended quotation. Usually, this is rendered visually by indentation. A URL for the source of the quotation may be given using the cite attribute, while a text representation of the source can be given using the cite element. + +Adapted from [blockquote: The Block Quotation element, from MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/blockquote) + + + +![test](https://media.discordapp.net/attachments/413884110667251722/886474243662037062/image1.jpg) + + + +Blogposts whose filename starts with a \_ will not show up on the /blogs page, but will still be accessible from the url (keep in mind that the file is still going to be publicly accessible on GitHub). diff --git a/blogposts/todo.md b/blogposts/todo.md index 6629663..5628386 100644 --- a/blogposts/todo.md +++ b/blogposts/todo.md @@ -2,14 +2,13 @@ title: "Todo" author: "Monty" author_image: "https://www.github.com/montylion.png" -date: "19 January 2038" -caption: "A todo list" +date: "January 19, 2038" +caption: "A todo list (delete file when done)" cover_image: "https://i.imgur.com/sOWLwO5.png" --- -- -Redesign by the one true design god jvs, then -- -Add mobile support -- -Add custom opengraph for each post +A todo list (delete file when done) +- [ ] Redesign by the one true design god jvs +- [x] Add mobile support +- [x] Add css styling for all elements supported by markdown +- [ ] Fix navbar \ No newline at end of file diff --git a/locales/US_en.json b/locales/US_en.json index 8d96a8b..b9e0f07 100644 --- a/locales/US_en.json +++ b/locales/US_en.json @@ -3,7 +3,8 @@ "about": "About", "faq": "FAQ", "credits": "Credits", - "progress": "Progress" + "progress": "Progress", + "blog": "Blog" }, "hero": { "subtitle": "Game servers", diff --git a/public/assets/css/blog.css b/public/assets/css/blog.css index 787eb1d..ea1efcf 100644 --- a/public/assets/css/blog.css +++ b/public/assets/css/blog.css @@ -1,61 +1,51 @@ .blog-card { + display: flex; + flex-flow: row nowrap; padding: 0; margin: 0 auto; max-width: 1100px; - margin-top: 30px; + margin-bottom: 30px; text-decoration: none; - display: flex; - flex-flow: row nowrap; position: relative; + border-radius: 10px; + overflow: hidden; } -.blog-card .left { - flex: 2 0 55%; +.blog-card .post-info { + flex: 2 0 45%; padding: 40px; -} - -.blog-card .right { display: flex; - border-radius: 0 10px 10px 0; - height: 260px; - width: 45%; -} - -.blog-card .right img { - width: 100%; - height: 100%; - object-fit: cover; - border-radius: 0 10px 10px 0; -} - -.blog-card h2 { - color: white; - margin-top: 0; -} - -.blog-card p, .post-info { + flex-flow: column; color: var(--text-secondary); } -.blog-card .date { - margin-bottom: 0; - font-weight: bold; - color: var(--text); + +.blog-card .post-info .title { + color: white; + margin: 0; } -.blog-card img { - - border-radius: 4px; + +.blog-card .post-info .caption { + margin: 4px 0 32px 0; } -.blog-card .post-info { + +.blog-card .pub-info { display: flex; flex-wrap: wrap; align-items: center; justify-content: left; - position: absolute; - bottom: 40px; + margin-top: auto; } -.blog-card .post-info > * + * { - margin-left: .5em; + +.blog-card .pub-info .date { + font-weight: bold; + color: var(--text); } + +.blog-card .pub-info > * { + margin-right: .5em; + margin-top: .2em; +} + .blog-card .profile { display: inline-grid; grid-template-columns: 30px auto; @@ -63,9 +53,44 @@ font-weight: bold; color: var(--text); align-items: center; - height: 32px; /* So the post doesn't shift when the image gets loaded */ + height: 32px; } .blog-card .profile img { + border-radius: 4px; border: 1px solid rgba(255, 255, 255, 0.1); max-width: 100%; +} + +.blog-card .cover { + flex: 45%; +} + +@media screen and (max-width: 600px) { + .blog-card { + flex-flow: column; + } + .blog-card .post-info { + padding: 30px; + } + .blog-card .cover { + order: -1; + min-height: 200px; + } +} + +@media screen and (max-width: 400px) { + .blog-card { + + max-width: none; + border-radius: 0; + } + + .wrapper { + width: 100%; + } + + header { + width: 90%; + margin: 35px auto; + } } \ No newline at end of file diff --git a/public/assets/css/blogpost.css b/public/assets/css/blogpost.css index 46e9a9a..22993c5 100644 --- a/public/assets/css/blogpost.css +++ b/public/assets/css/blogpost.css @@ -1,58 +1,160 @@ .blog-card { - padding: 60px; - margin: 0 auto; - max-width: 1100px; - margin-top: 50px; + padding: 60px; + margin: 0 auto; + max-width: 1100px; + margin-top: 50px; + color: var(--text-secondary); +} + +.blog-card h1, +.blog-card h2, +.blog-card h3, +.blog-card h4, +.blog-card h5, +.blog-card h6, +.blog-card strong, +.blog-card a, +.blog-card a * { + color: white; } .blog-card .title { - margin: 0; + margin: 0; } -.blog-card p, .post-info { - color: var(--text-secondary); - margin-bottom: 30px; +.blog-card p, +.post-info { + color: var(--text-secondary); + margin-bottom: 30px; } .blog a { - color: var(--text-secondary); + color: var(--text-secondary); } .blog-card .date { - margin-bottom: 0; - font-weight: bold; - color: var(--text); -} -.blog-card iframe { - width: 100%; - aspect-ratio: 16/9; - border-radius: 4px; - border: 1px solid rgba(255, 255, 255, 0.1); + margin-bottom: 0; + font-weight: bold; + color: var(--text); } + .blog-card img { - max-width: 100%; - margin: 10px auto; - display: block; + max-width: 100%; + max-height: 800px; + margin: 10px auto; + display: block; + border-radius: 4px; + border: 1px solid rgba(255, 255, 255, 0.1); +} +.blog-card img.emoji { + display: inline; + margin: 0; + border: none; +} + +.blog-card video { + width: 100%; + border-radius: 4px; + border: 1px solid rgba(255, 255, 255, 0.1); +} + +.blog-card iframe { + width: 100%; + aspect-ratio: 16/9; + border-radius: 4px; + border: 1px solid rgba(255, 255, 255, 0.1); +} + +.blog-card table { + border-radius: 4px; + border-collapse: collapse; + background: #31375E; + margin-bottom: 30px; + overflow: hidden; + color: var(--text-secondary); +} +.blog-card table th { + padding: 8px 12px; + background: #3F4778; + color: white; +} +.blog-card table td { + padding: 8px 12px; + vertical-align: top; + border-radius: inherit; +} +.blog-card table tr:nth-child(even) { + background: #2A2F50; +} + +.blog-card pre code { + border-radius: 4px; + margin-bottom: 30px; +} + +.blog-card input[type="checkbox"] { + appearance: none; + -webkit-appearance: none; + display: inline-block; + background: var(--btn-secondary); + padding: 12px; + margin: 4px; border-radius: 4px; - border: 1px solid rgba(255, 255, 255, 0.1); + vertical-align: -60%; +} +.blog-card input[type="checkbox"]:checked { + content: 'checkboxtest'; + background: no-repeat center/contain url(../images/check.svg), var(--btn-secondary); +} + +.blog-card hr { + border: 1px solid var(--text-secondary); + margin: 30px 0; +} + +.blog-card blockquote { + border-left: 2px solid var(--text-secondary); + padding: 8px 24px; + margin: 0; + margin-bottom: 30px; } .blog-card .post-info { - display: flex; - flex-wrap: wrap; - align-items: center; + display: flex; + flex-wrap: wrap; + align-items: center; } .blog-card .post-info > * + * { - margin-left: .5em; + margin-left: 0.5em; } .blog-card .profile { - display: inline-grid; - grid-template-columns: 30px auto; - grid-gap: 10px; - font-weight: bold; - color: var(--text); - align-items: center; - height: 52px; /* So the post doesn't shift when the image gets loaded */ + display: inline-grid; + grid-template-columns: 30px auto; + grid-gap: 10px; + font-weight: bold; + color: var(--text); + align-items: center; + height: 52px; } -footer { - margin-top: 80px; +@media screen and (max-width: 800px) { + .blog-card { + padding: 60px; + margin: 0; + max-width: none; + border-radius: 0; + } + + .wrapper { + width: 100%; + } + + header { + width: 90%; + margin: 35px auto; + } +} + +@media screen and (max-width: 600px) { + .blog-card { + padding: 40px 5vw; + } } \ No newline at end of file diff --git a/public/assets/css/highlightjs.css b/public/assets/css/highlightjs.css new file mode 100644 index 0000000..d0def53 --- /dev/null +++ b/public/assets/css/highlightjs.css @@ -0,0 +1,91 @@ +/** + * Adapted from Shades of Purple Theme — for Highlightjs. + * + * @author (c) Ahmad Awais + * @link GitHub Repo → https://github.com/ahmadawais/Shades-of-Purple-HighlightJS + * @version 1.5.0 + */ + + .hljs { + background: var(--btn-secondary); + color: #e3dfff; + font-weight: normal; + } + + .hljs-subst { + color: #e3dfff; + } + + .hljs-title { + color: #fad000; + font-weight: normal; + } + + .hljs-name { + color: #a1feff; + } + + .hljs-tag { + color: #ffffff; + } + + .hljs-attr { + color: #f8d000; + font-style: italic; + } + + .hljs-built_in, + .hljs-selector-tag, + .hljs-section { + color: #fb9e00; + } + + .hljs-keyword { + color: #fb9e00; + } + + .hljs-string, + .hljs-attribute, + .hljs-symbol, + .hljs-bullet, + .hljs-addition, + .hljs-code, + .hljs-regexp, + .hljs-selector-class, + .hljs-selector-attr, + .hljs-selector-pseudo, + .hljs-template-tag, + .hljs-quote, + .hljs-deletion { + color: #4cd213; + } + + .hljs-meta, + .hljs-meta .hljs-string { + color: #fb9e00; + } + + .hljs-comment { + color: #ac65ff; + } + + .hljs-keyword, + .hljs-selector-tag, + .hljs-literal, + .hljs-name, + .hljs-strong { + font-weight: normal; + } + + .hljs-literal, + .hljs-number { + color: #fa658d; + } + + .hljs-emphasis { + font-style: italic; + } + + .hljs-strong { + font-weight: bold; + } \ No newline at end of file diff --git a/public/assets/css/main.css b/public/assets/css/main.css index 6bdae04..8bb5ee0 100644 --- a/public/assets/css/main.css +++ b/public/assets/css/main.css @@ -659,7 +659,7 @@ footer { } -@media screen and (max-width: 500px) { +@media screen and (max-width: 550px) { .selected-locale .locale-names { display: none; } @@ -670,6 +670,10 @@ footer { margin-right: 12px; } + .locale-dropdown { + width: fit-content; + } + } @media screen and (max-width: 400px) { diff --git a/public/assets/images/check.svg b/public/assets/images/check.svg new file mode 100644 index 0000000..7b165ec --- /dev/null +++ b/public/assets/images/check.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/routers/blog.js b/src/routers/blog.js index 0ccd227..b12840f 100644 --- a/src/routers/blog.js +++ b/src/routers/blog.js @@ -20,6 +20,7 @@ router.get('/', async (request, response) => { // We get the info for each blogpost, ignoring the ones starting with _ const postList = fileList .filter(filename => !filename.startsWith('_')) + .filter(filename => filename.endsWith('.md')) //Ignores other files/folders .map((filename) => { const slug = filename.replace('.md', ''); const rawPost = fs.readFileSync(path.join('blogposts', `${filename}`), 'utf-8'); @@ -28,6 +29,7 @@ router.get('/', async (request, response) => { slug, postInfo }; }); + postList.sort((a, b) => { return new Date(b.postInfo.date) - new Date(a.postInfo.date); }); diff --git a/views/blog.handlebars b/views/blog.handlebars index df17e65..c83bb12 100644 --- a/views/blog.handlebars +++ b/views/blog.handlebars @@ -14,10 +14,10 @@ {{#each postList }} -
-

{{{ this.postInfo.title }}}

-

{{{ this.postInfo.caption }}}

-