diff --git a/_config.yml b/_config.yml index 121b95580a..de615be21d 100644 --- a/_config.yml +++ b/_config.yml @@ -1,5 +1,15 @@ # Site settings +defaults: + - + scope: + path: "_posts" + type: "posts" + values: + layout: "post" + menu: blog + lang: en + # Build settings markdown: kramdown diff --git a/_includes/blog/posts-menu.md b/_includes/blog/posts-menu.md new file mode 100644 index 0000000000..5afe3f32c7 --- /dev/null +++ b/_includes/blog/posts-menu.md @@ -0,0 +1,12 @@ +
+

+ Posts +

+ +
diff --git a/_includes/blog/tags-menu.md b/_includes/blog/tags-menu.md new file mode 100644 index 0000000000..8b722e9cec --- /dev/null +++ b/_includes/blog/tags-menu.md @@ -0,0 +1,10 @@ + diff --git a/_includes/header/header-en.html b/_includes/header/header-en.html index fd660ebc81..f160f6d195 100644 --- a/_includes/header/header-en.html +++ b/_includes/header/header-en.html @@ -141,6 +141,23 @@ +
  • + +
  • + + {% include head.html %} + + + +
    + + {% include header/header-{{ page.lang }}.html %} + + {% include blog/posts-menu.md %} + +
    +
    + {% if page.title %} +

    {{page.title}}

    + {% endif %} + {% if page.sub_title %} +

    {{page.sub_title}}

    + {% endif %} +
    + {% if page.author %} +
    By {{page.author}}
    + {% endif %} +
    {{page.date| date: "%d %b %Y" }}
    +
    + {{ content }} +
    +
    + + {% include footer/footer-{{ page.lang }}.html %} + + + + diff --git a/_posts/2024-07-16-welcome-post.md b/_posts/2024-07-16-welcome-post.md new file mode 100644 index 0000000000..e91585cd58 --- /dev/null +++ b/_posts/2024-07-16-welcome-post.md @@ -0,0 +1,18 @@ +--- +title: Welcome to The Express Blog! +tags: site-admin +author: Rand McKinney and Chris Del +--- + +Welcome to the new Express blog! The blog is meant to be a primary means of communication for the Express technical committee (TC). While we currently have other channels such as X, LinkedIn, and of course GitHub, there's no authoritative "soapbox" for announcements and general communication. + +Initially, the Express blog will be a venue: +- For periodic announcements of new releases, pre-releases, plans, and ongoing work on the project. +- For the Express TC to discuss issues of particular importance to the Express community. +- To highlight security issues or other urgent information. + +Eventually, we hope the blog will evolve into a more general communication hub for the entire Express community; for example to share examples, tips, and experiences with the Express ecosystem and other information that's not simply technical documentation or GitHub discussion. + +Initially, posts will be written by TC members (potentially collaborating others), mainly because we don't have bandwidth to review general posts from the broader community. Eventually, we would love to open up the blog for broader contributions, but for now the focus is on trying to release Express 5.0, and the reality of an open-source project is that everyone has finite time to contribute. + +If you think you have a great idea for a post for future consideration, feel free to pitch the idea! The best approach is to open a new issue, and then after appropriate discussion, open a PR. We've also written up simple [instructions to create a blog post](/en/blog/write-post.html). diff --git a/css/dark-theme.css b/css/dark-theme.css index 675d8e5428..3e8b4a76f8 100644 --- a/css/dark-theme.css +++ b/css/dark-theme.css @@ -1,11 +1,14 @@ :root { --main_dark_bg: #010409; --second_dark_bg: #0d1117; + --darker_hover: #171b20;; --dark_hover: #383838; --second_dark_hover: #484848; - --dark_text: #e6edf3; + --dark_inner_text: #888888; --dark_header_text: silver; - --dark_inner_text: grey; + --dark_main_text: #e6edf3; + --dark_bright_text: wheat; + --dark_border: #ddd; --link: #259dff; } #theme-icon-container { @@ -40,24 +43,24 @@ html.dark-mode #theme-icon-container .hidden-dark { display: none; } html.dark-mode #theme-icon-container { - color: var(--dark_text); + color: var(--dark_main_text); background-color: var(--second_dark_bg); } html.dark-mode > body { background: var(--main_dark_bg); - color: var(--dark_text); + color: var(--dark_main_text); } html.dark-mode header { background-color: var(--second_dark_bg); - color: var(--dark_text); + color: var(--dark_main_text); } html.dark-mode #logo > a { - color: var(--dark_text); + color: var(--dark_main_text); } /* navbar links/drop down menu links */ html.dark-mode #navbar ul#navmenu li a, html.dark-mode #navbar ul#navmenu li.dropit-trigger a { - color: var(--dark_text); + color: var(--dark_main_text); } /* first drop down link - some js is adding current class */ html.dark-mode #navbar ul#navmenu li a.current { @@ -82,12 +85,12 @@ html.dark-mode #navbar > span.algolia-autocomplete > input { } html.dark-mode #navbar > span.algolia-autocomplete > input, html.dark-mode #navbar > span.algolia-autocomplete > input::placeholder { - color: var(--dark_text); + color: var(--dark_main_text); } /* search bar french */ :lang(fr) html.dark-mode #navbar ul#navmenu > span.algolia-autocomplete > input { background-color: var(--second_dark_bg); - color: var(--dark_text); + color: var(--dark_main_text); } /* search bar fixes uz, ru, de, fr */ :lang(uz) span.algolia-autocomplete { @@ -108,7 +111,7 @@ html.dark-mode #navbar > span.algolia-autocomplete > input::placeholder { max-width: 100%; } html.dark-mode #navbar ul#navmenu > span.algolia-autocomplete > input::placeholder { - color: var(--dark_text); + color: var(--dark_main_text); } html.dark-mode div#overlay { opacity: 0.5; @@ -124,13 +127,13 @@ html.dark-mode div#overlay { /* mobile menu inner links hover */ html.dark-mode div#navbar .menu ul.dropit-submenu a:hover { background: var(--second_dark_hover); - color: var(--dark_text) !important; + color: var(--dark_main_text) !important; } } html.dark-mode .doc-box.doc-info, html.dark-mode .doc-box.doc-notice, html.dark-mode .doc-box.doc-warn { - color: var(--dark_text); + color: var(--dark_main_text); background: var(--main_dark_bg); } html.dark-mode .doc-box.doc-info pre.language-javascript { @@ -142,14 +145,14 @@ html.dark-mode h3, html.dark-mode code, html.dark-mode em, html.dark-mode strong { - color: var(--dark_text); + color: var(--dark_main_text); } html.dark-mode pre { background: var(--second_dark_bg); } /* index.html */ html.dark-mode #description .express > a { - color: var(--dark_text); + color: var(--dark_main_text); } html.dark-mode #install-command { background: var(--main_dark_bg); @@ -158,7 +161,7 @@ html.dark-mode #announcements { background: var(--main_dark_bg); } html.dark-mode #boxes div > h3 { - color: var(--dark_text); + color: var(--dark_main_text); } /* basic-routing.htlm */ html.dark-mode [class*='language-'] { @@ -171,11 +174,11 @@ html.dark-mode .token.operator { /* debugging.htlm */ html.dark-mode table tr:first-child th { background-color: var(--second_dark_bg); - color: var(--dark_text); + color: var(--dark_main_text); } /* api pages */ html.dark-mode #menu li > * { - color: var(--dark_text); + color: var(--dark_main_text); } html.dark-mode #menu li ul li > em { color: var(--dark_header_text); @@ -197,14 +200,14 @@ html.dark-mode .ds-dropdown-menu .ds-dataset-1 { } html.dark-mode .ds-dropdown-menu .ds-dataset-1 .ds-suggestion a { background-color: var(--second_dark_bg); - color: var(--dark_text); + color: var(--dark_main_text); } html.dark-mode .ds-dropdown-menu .ds-dataset-1 .ds-suggestions .algolia-docsearch-suggestion--category-header { - color: var(--dark_text); + color: var(--dark_main_text); } html.dark-mode .ds-dropdown-menu @@ -220,7 +223,7 @@ html.dark-mode .ds-suggestions .algolia-docsearch-suggestion--wrapper .algolia-docsearch-suggestion--title { - color: var(--dark_text); + color: var(--dark_main_text); } html.dark-mode .ds-dropdown-menu @@ -228,7 +231,7 @@ html.dark-mode .ds-suggestions .algolia-docsearch-suggestion--wrapper .algolia-docsearch-suggestion--text { - color: var(--dark_text); + color: var(--dark_main_text); } html.dark-mode .ds-dropdown-menu @@ -242,4 +245,23 @@ html.dark-mode .ds-suggestion.ds-cursor .algolia-docsearch-suggestion--title, html.dark-mode .ds-suggestion.ds-cursor .algolia-docsearch-suggestion--content{ background-color: var(--dark_hover); } - +html.dark-mode .blog-post{ + background-color: initial; + border: 1px solid var(--dark_border); + transition: 0.3s; +} +html.dark-mode .blog-post:hover{ + background-color: var(--darker_hover); +} +html.dark-mode .blog-title > a{ + color: var(--dark_main_text); +} +html.dark-mode .blog-excerpt{ + color: var(--dark_bright_text); +} +html.dark-mode #blog-side-menu-container h3 a{ + color: var(--dark_header_text); +} +html.dark-mode #blog-side-menu > li > a{ + color: var(--dark_inner_text); +} \ No newline at end of file diff --git a/css/style.css b/css/style.css index 66898e4e09..53f6e334dc 100644 --- a/css/style.css +++ b/css/style.css @@ -739,7 +739,9 @@ footer { /* secondary menu */ -#menu { +#menu, +#tags-side-menu, +#blog-side-menu-container { position: fixed; margin: 0; padding: 0 10px 0 0; @@ -751,7 +753,23 @@ footer { overflow-y: auto; } -#menu em { +#blog-side-menu-container { + max-width: 210px; +} + +#blog-side-menu-container li { + max-width: 100%; + margin-bottom: 5px; +} + +#blog-side-menu { + list-style: none; + padding: 0; +} + +#menu em, +#tags-side-menu em, +#blog-side-menu em{ font-weight: bold; color: #888; } @@ -759,29 +777,53 @@ footer { #menu li { list-style: none; } +#tags-side-menu li { + list-style: none; + font-size: 15px; + font-weight: bold; +} -#menu ul { +#menu ul, +#tags-side-menu ul { height: 0; overflow: hidden; } -#menu ul.active { +#menu ul.active, +#tags-side-menu ul.active { height: auto; padding: 0; } -#menu > li > a { - color: #353535; +#menu > li > a, +#tags-side-menu > li > a, +#blog-side-menu > li > a { font-weight: bold; - font-size: 15px; + font-size: 13px; +} + +#blog-side-menu > li > a { + color: #666 } -#menu ul a { +#blog-side-menu-container > h3 > a { + color: #353535 +} + + + +#menu ul a, +#tags-side-menu ul a { color: #555; padding-right: 7px; } +#tags-side-menu ul a{ + font-size: 13px; + font-weight:initial; +} -#menu ul a.active { +#menu ul a.active, +#tags-side-menu ul a.active { color: #259dff; } @@ -794,12 +836,12 @@ h2 a { #q { display: none; height: 2.5em; - min-width: 100%; + max-width: 100%; padding: 5px; } .algolia-autocomplete { - min-width: 12em; + max-width: 9em; top: -0.2em; margin-right: 3px; } @@ -807,6 +849,13 @@ h2 a { .algolia-autocomplete #q { display: initial } +/* search-bar desktop re-sizing */ +@media all and (min-width: 950px) { + .algolia-autocomplete { + margin-right:15px; + max-width: 12em; + } +} /* responsive */ @@ -882,7 +931,9 @@ h2 a { font-weight: normal; } - #menu { + #menu, + #tags-side-menu, + #blog-side-menu-container { display: none; } @@ -1195,3 +1246,130 @@ h2 a { #mw-list ul li { margin-left: -20px; } +/* Blog page styles*/ +#blog-doc { + margin: 0 10px; +} +#blog-doc:has(> h1#express-blog), +#blog-doc:has(> h1#write-a-blog-post) { + min-height: 300px; +} +#blog-doc .blog-details ~ p > img { + width: 200px; + float: right; +} +#blog-doc p { + font-size: 1.1em; +} +.blog-posts { + display: flex; + flex-direction: column; + row-gap: 10px; +} +.blog-post { + width: 100%; + background-color: #eee; + display: flex; + padding: 10px; + flex-direction: column; + justify-content: space-between; + box-shadow: 2px 3px #E0E0E0; + border-radius: 5px; + border: 1px solid #808080; + transition: 0.1s; +} +.blog-post:hover { + background-color: #D3D3D3; + border: 1px solid #303030; +} +.blog-post img { + max-width: 100%; + max-height: 100%; + object-fit: cover; +} +.blog-post .blog-details { + display: flex; + flex-direction: column; +} +.blog-details div:first-child { + margin-bottom: 5px; +} +.blog-tag { + font-size: 12px; +} +.blog-title { + font-size: 1.3rem; + line-height: 1.5rem; + font-weight: 500; + padding-right: .2em; +} +.blog-title a { + color: #000; +} +.blog-excerpt { + color: initial; + font-size: .75rem; +} +.blog-img { + max-width: 100%; + margin: auto; +} +.blog-author { + font-style: italic; +} +.blog-date { + font-weight: bold; + font-size: 85%; +} +/* mobile-only */ +@media (max-width: 500px) { + #blog-doc { + display: flex; + flex-direction: column; + align-items: center; + margin: 0; + padding-right: 10px; + } + #blog-doc .blog-details + p { + display: flex; + flex-direction: column; + align-items: center; + } + #blog-doc .blog-details + p > img { + margin-bottom: 15px; + } +} +/* blog tablet and up*/ +@media (min-width: 768px) { + .blog-post { + margin: auto; + } + .blog-tags { + margin-bottom: 20px; + } + .blog-title { + font-size: 1.3rem; + margin-bottom: 20px; + line-height: 1.5rem; + } + .blog-post .blog-details { + display: flex; + flex-direction: row; + margin-left: 1rem; + font-size: 90%; + } + .blog-post .blog-details div:first-child { + margin-right: 20px; + } + .blog-details { + font-size: 1rem; + } + .blog-excerpt { + line-height: initial; + font-size: .85rem; + font-weight: 300; + margin-top: auto; + margin-bottom: 10px; + max-width: 80%; + } +} diff --git a/en/blog/posts.md b/en/blog/posts.md new file mode 100644 index 0000000000..ca64543c8f --- /dev/null +++ b/en/blog/posts.md @@ -0,0 +1,28 @@ +--- +layout: post +title: Express Blog Posts +menu: blog +lang: en +redirect_from: "/blog/posts.html" +--- + +Want to write a post? See the submission [guidelines.](/en/blog/write-post.html) + +{% if site.posts.size != 0 %} +
    +{% for post in site.posts %} +
    + +
    +
    By {{ post.author }}
    +
    {{ post.date | date:"%b %d, %Y" }}
    +
    +
    {{post.excerpt | truncate: 240 | markdownify }}
    +
    +{% endfor %} +
    +{% else %} + There are currently no blog posts. +{% endif %} diff --git a/en/blog/write-post.md b/en/blog/write-post.md new file mode 100644 index 0000000000..5b8f6c4a6c --- /dev/null +++ b/en/blog/write-post.md @@ -0,0 +1,46 @@ +--- +layout: post +title: How to write a blog post +menu: blog +lang: en +redirect_from: "/blog/write.html" +--- + +![Blogger]({{site.url}}/images/blogger.jpg) + +If you have an idea for a blog post, follow these steps to propose it and potentially get it published! + +1. ### Propose your post +Before taking the time to write a post, please confirm that we will be able to publish it. We're looking for topics specifically related to Express, and so we want to pre-approve all posts. For the moment, this means we aren't accepting any unsolicited posts. To propose a blog post, [open an issue](https://github.com/expressjs/expressjs.com/issues) entitled `Blog post proposal: `. + + +1. ### Fork the repository +If the Express TC accepts your proposal, start to write your post by forking the [expressjs.com](https://github.com/expressjs/expressjs.com) repository and cloning it to your local machine. Once you open a pull request, you'll be able to preview your post on GitHub. See step six below. + + Optional: To run the site locally and preview your post before opening a PR, see the [setup instructions in the README](https://github.com/expressjs/expressjs.com?tab=readme-ov-file#expressjscom). + {: .doc-box .doc-info} + +1. ### Create a new file +Create a new file in the `_posts` directory named using following the format: `YYYY-MM-DD-title.md`. + +1. ### Add the required front matter + Copy the following front matter, including the dotted lines, and paste it at the top of file you just created. Replace the placeholder values with as desired. + + ```yaml + --- + title: + sub_title: + date: + tags: + author: + --- + ``` +2. ### Add your content + Finally, start writing your content below the front matter. Use standard markdown formatting. + +1. ### Open a pull request (PR) + Once you open a PR, you will be able to preview your results: There will be a section on the page entitled `Deploy Preview for expressjscom-preview ready!` Click the link to see the site rendered from your fork/branch. + + You can use this feature over multiple commits to refine your post by making a `draft` pull request. Once it's ready for review, switch it to a formal PR. + + \ No newline at end of file diff --git a/images/blogger.jpg b/images/blogger.jpg new file mode 100644 index 0000000000..52bca213fc Binary files /dev/null and b/images/blogger.jpg differ diff --git a/js/app.js b/js/app.js index 11a0ecebeb..a648bbf455 100644 --- a/js/app.js +++ b/js/app.js @@ -152,6 +152,11 @@ $(function(){ } }) + $('#tags-side-menu li').on('click', function() { + // Remove prev 'active's + $(this).next().siblings().removeClass('active'); + $(this).next().addClass('active') + }) // show mobile menu $('#nav-button').click(function () { @@ -173,6 +178,7 @@ $(function(){ $('#guide-menu').dropit({ action: 'click' }) $('#advanced-topics-menu').dropit({ action: 'click' }) $('#resources-menu').dropit({ action: 'click' }) + $('#blog-menu').dropit({ action: 'click' }) $('#lb-menu').dropit({ action: 'click' }) $('#changelog-menu').dropit({ action: 'click' }) } @@ -182,6 +188,7 @@ $(function(){ $('#guide-menu').dropit({ action: 'mouseenter' }) $('#advanced-topics-menu').dropit({ action: 'mouseenter' }) $('#resources-menu').dropit({ action: 'mouseenter' }) + $('#blog-menu').dropit({ action: 'mouseenter' }) $('#lb-menu').dropit({ action: 'mouseenter' }) $('#changelog-menu').dropit({ action: 'mouseenter' }) }