|
| 1 | +--- |
| 2 | +title: New Blogging features in Razor SSG |
| 3 | +summary: Explore the new Blogging Features in Razor SSG |
| 4 | +tags: razor, markdown, blog, dev |
| 5 | +image: https://images.unsplash.com/photo-1486312338219-ce68d2c6f44d?crop=entropy&fit=crop&h=1000&w=2000 |
| 6 | +author: Demis Bellot |
| 7 | +draft: true |
| 8 | +--- |
| 9 | + |
| 10 | + |
| 11 | + |
| 12 | +## New Blogging features in Razor SSG |
| 13 | + |
| 14 | +We've continued improving the [Razor SSG](https://razor-ssg.web-templates.io) template for static generated websites |
| 15 | +and Blogs. |
| 16 | + |
| 17 | +### RSS Feed |
| 18 | + |
| 19 | +Razor SSG websites now generates a valid RSS Feed for its blog to support their readers who'd prefer to read blog posts |
| 20 | +with their favorite RSS reader: |
| 21 | + |
| 22 | +<div class="not-prose my-8"> |
| 23 | + <a href="https://razor-ssg.web-templates.io/feed.xml"> |
| 24 | + <div class="block flex justify-center shadow hover:shadow-lg rounded overflow-hidden"> |
| 25 | + <img class="max-w-3xl py-8" src="/img/posts/razor-ssg/valid-rss.png"> |
| 26 | + </div> |
| 27 | + </a> |
| 28 | + <div class="mt-4 flex justify-center"> |
| 29 | + <a class="text-indigo-600 hover:text-indigo-800" href="https://razor-ssg.web-templates.io/feed.xml">https://razor-ssg.web-templates.io/feed.xml</a> |
| 30 | + </div> |
| 31 | +</div> |
| 32 | + |
| 33 | +### New Markdown Containers |
| 34 | + |
| 35 | +All Razor Press's [Markdown Containers](https://razor-press.web-templates.io/containers) are also available in Razor SSG |
| 36 | +websites for enabling rich, wrist-friendly consistent markup in your Markdown pages, e.g: |
| 37 | + |
| 38 | +```md |
| 39 | +::: info |
| 40 | +This is an info box. |
| 41 | +::: |
| 42 | + |
| 43 | +::: tip |
| 44 | +This is a tip. |
| 45 | +::: |
| 46 | + |
| 47 | +::: warning |
| 48 | +This is a warning. |
| 49 | +::: |
| 50 | + |
| 51 | +::: danger |
| 52 | +This is a dangerous warning. |
| 53 | +::: |
| 54 | + |
| 55 | +:::copy |
| 56 | +Copy Me! |
| 57 | +::: |
| 58 | +``` |
| 59 | + |
| 60 | +::: info |
| 61 | +This is an info box. |
| 62 | +::: |
| 63 | + |
| 64 | +::: tip |
| 65 | +This is a tip. |
| 66 | +::: |
| 67 | + |
| 68 | +::: warning |
| 69 | +This is a warning. |
| 70 | +::: |
| 71 | + |
| 72 | +::: danger |
| 73 | +This is a dangerous warning. |
| 74 | +::: |
| 75 | + |
| 76 | +:::copy |
| 77 | +Copy Me! |
| 78 | +::: |
| 79 | + |
| 80 | +See [Markdown Containers docs](https://razor-press.web-templates.io/containers) for more examples and how to |
| 81 | +implement your own [Custom Markdown containers](https://razor-press.web-templates.io/containers#implementing-block-containers). |
| 82 | + |
| 83 | +### Support for Includes |
| 84 | + |
| 85 | +Markdown fragments can be added to `_pages/_include` - a special folder rendered with |
| 86 | +[Pages/Includes.cshtml](https://github.com/NetCoreTemplates/razor-ssg/blob/main/MyApp/Pages/Includes.cshtml) using |
| 87 | +an [Empty Layout](https://github.com/NetCoreTemplates/razor-ssg/blob/main/MyApp/Pages/Shared/_LayoutEmpty.cshtml) |
| 88 | +which can be included in other Markdown and Razor Pages or fetched on demand with Ajax. |
| 89 | + |
| 90 | +Markdown Fragments can be then included inside other markdown documents with the `::include` inline container, e.g: |
| 91 | + |
| 92 | +:::pre |
| 93 | +::include vue/formatters.md:: |
| 94 | +::: |
| 95 | + |
| 96 | +Where it will be replaced with the HTML rendered markdown contents of fragments maintained in `_pages/_include`. |
| 97 | + |
| 98 | +### Include Markdown in Razor Pages |
| 99 | + |
| 100 | +Markdown Fragments can also be included in Razor Pages using the custom `MarkdownTagHelper.cs` `<markdown/>` tag: |
| 101 | + |
| 102 | +```html |
| 103 | +<markdown include="vue/formatters.md"></markdown> |
| 104 | +``` |
| 105 | + |
| 106 | +### Inline Markdown in Razor Pages |
| 107 | + |
| 108 | +Alternatively markdown can be rendered inline with: |
| 109 | + |
| 110 | +```html |
| 111 | +<markdown> |
| 112 | +## Using Formatters |
| 113 | + |
| 114 | +Your App and custom templates can also utilize @servicestack/vue's |
| 115 | +[built-in formatting functions](href="/vue/use-formatters). |
| 116 | +</markdown> |
| 117 | +``` |
| 118 | + |
| 119 | +### Meta Headers support for Twitter cards and Improved SEO |
| 120 | + |
| 121 | +Blog Posts and Pages now include additional `<meta>` HTML Headers to enable support for |
| 122 | +[Twitter Cards](https://developer.twitter.com/en/docs/twitter-for-websites/cards/overview/abouts-cards) in both |
| 123 | +Twitter and Meta's new [threads.net](https://threads.net), e.g: |
| 124 | + |
| 125 | +<div class="not-prose my-8 flex justify-center"> |
| 126 | + <a class="block max-w-2xl" href="https://www.threads.net/@servicestack/post/CvIFobPBs5h"> |
| 127 | + <div class="block flex justify-center shadow hover:shadow-lg rounded overflow-hidden"> |
| 128 | + <img class="py-8" src="/img/posts/razor-ssg/twitter-cards.png"> |
| 129 | + </div> |
| 130 | + </a> |
| 131 | +</div> |
| 132 | + |
| 133 | +### Posts can include Vue Components |
| 134 | + |
| 135 | +Blog Posts can now embed any global Vue Components directly in their Markdown, e.g: |
| 136 | + |
| 137 | +```html |
| 138 | +<getting-started></getting-started> |
| 139 | +``` |
| 140 | + |
| 141 | +Just like Pages and Docs they can also include specific JavaScript **.mjs** or **.css** in the `/wwwroot/posts` folder |
| 142 | +which will only be loaded for that post: |
| 143 | + |
| 144 | +<file-layout :files="{ |
| 145 | + wwwroot: { |
| 146 | + posts: { _: ['<slug>.mjs','<slug>.css'] }, |
| 147 | + } |
| 148 | +}"></file-layout> |
| 149 | + |
| 150 | +Now posts that need it can dynamically load large libraries like [Chart.js](https://www.chartjs.org) and use it |
| 151 | +inside a custom Vue component, e.g: |
| 152 | + |
| 153 | +```js |
| 154 | +import { ref, onMounted } from "vue" |
| 155 | +import { addScript } from "@servicestack/client" |
| 156 | +const addChartsJs = await addScript('../lib/js/chart.js') |
| 157 | + |
| 158 | +const ChartJs = { |
| 159 | + template:`<div><canvas ref="chart"></canvas></div>`, |
| 160 | + props:['type','data','options'], |
| 161 | + setup(props) { |
| 162 | + const chart = ref() |
| 163 | + onMounted(async () => { |
| 164 | + await addChartsJs |
| 165 | + const options = props.options || { |
| 166 | + responsive: true, |
| 167 | + legend: { position: "top" } |
| 168 | + } |
| 169 | + new Chart(chart.value, { |
| 170 | + type: props.type || "bar", |
| 171 | + data: props.data, |
| 172 | + options, |
| 173 | + }) |
| 174 | + }) |
| 175 | + return { chart } |
| 176 | + } |
| 177 | +} |
| 178 | + |
| 179 | +export default { |
| 180 | + components: { ChartJs } |
| 181 | +} |
| 182 | +``` |
| 183 | + |
| 184 | +Which allows the post to embed Chart.js charts using the custom `<chart-js>` Vue component and a JS Object literal, e.g: |
| 185 | + |
| 186 | +```html |
| 187 | +<chart-js :data="{ |
| 188 | + labels: [ |
| 189 | + //... |
| 190 | + ], |
| 191 | + datasets: [ |
| 192 | + //... |
| 193 | + ] |
| 194 | +}"></chart-js> |
| 195 | +``` |
| 196 | + |
| 197 | +Which the [Bulk Insert Performance](https://servicestack.net/posts/bulk-insert-performance) Blog Post uses extensively to embeds its |
| 198 | +Chart.js Bar charts: |
| 199 | + |
| 200 | +<chart-js :data="{ |
| 201 | + labels: [ |
| 202 | + '10,000 Rows', |
| 203 | + '100,000 Rows' |
| 204 | + ], |
| 205 | + datasets: [ |
| 206 | + { |
| 207 | + label: 'SQLite Memory', |
| 208 | + backgroundColor: 'rgba(201, 203, 207, 0.2)', |
| 209 | + borderColor: 'rgb(201, 203, 207)', |
| 210 | + borderWidth: 1, |
| 211 | + data: [17.066, 166.747] |
| 212 | + }, |
| 213 | + { |
| 214 | + label: 'SQLite Disk', |
| 215 | + backgroundColor: 'rgba(255, 99, 132, 0.2)', |
| 216 | + borderColor: 'rgb(255, 99, 132)', |
| 217 | + borderWidth: 1, |
| 218 | + data: [20.224, 199.697] |
| 219 | + }, |
| 220 | + { |
| 221 | + label: 'PostgreSQL', |
| 222 | + backgroundColor: 'rgba(153, 102, 255, 0.2)', |
| 223 | + borderColor: 'rgb(153, 102, 255)', |
| 224 | + borderWidth: 1, |
| 225 | + data: [14.389, 115.645] |
| 226 | + }, |
| 227 | + { |
| 228 | + label: 'MySQL', |
| 229 | + backgroundColor: 'rgba(54, 162, 235, 0.2)', |
| 230 | + borderColor: 'rgb(54, 162, 235)', |
| 231 | + borderWidth: 1, |
| 232 | + data: [64.389, 310.966] |
| 233 | + }, |
| 234 | + { |
| 235 | + label: 'MySqlConnector', |
| 236 | + backgroundColor: 'rgba(255, 159, 64, 0.2)', |
| 237 | + borderColor: 'rgb(255, 159, 64)', |
| 238 | + borderWidth: 1, |
| 239 | + data: [64.427, 308.574] |
| 240 | + }, |
| 241 | + { |
| 242 | + label: 'SQL Server', |
| 243 | + backgroundColor: 'rgba(255, 99, 132, 0.2)', |
| 244 | + borderColor: 'rgb(255, 99, 132)', |
| 245 | + borderWidth: 1, |
| 246 | + data: [89.821, 835.181] |
| 247 | + } |
| 248 | + ] |
| 249 | +}"></chart-js> |
| 250 | + |
| 251 | +### Light and Dark Mode Query Params |
| 252 | + |
| 253 | +You can link to Dark and Light modes of your Razor SSG website with the `?light` and `?dark` query string params: |
| 254 | + |
| 255 | +- [https://razor-ssg.web-templates.io/?dark](https://razor-ssg.web-templates.io/?dark) |
| 256 | +- [https://razor-ssg.web-templates.io/?light](https://razor-ssg.web-templates.io/?light) |
| 257 | + |
| 258 | +### Blog Post Authors can have threads.net and Mastodon links |
| 259 | + |
| 260 | +The social links for Blog Post Authors can now include [threads.net](https://threads.net) and [mastodon.social](https://mastodon.social) links, e.g: |
| 261 | + |
| 262 | +```json |
| 263 | +{ |
| 264 | + "AppConfig": { |
| 265 | + "BlogImageUrl": "https://servicestack.net/img/logo.png", |
| 266 | + "Authors": [ |
| 267 | + { |
| 268 | + "Name": "Lucy Bates", |
| 269 | + |
| 270 | + "ProfileUrl": "img/authors/author1.svg", |
| 271 | + "TwitterUrl": "https://twitter.com/lucy", |
| 272 | + "ThreadsUrl": "https://threads.net/@lucy", |
| 273 | + "GitHubUrl": "https://github.com/lucy" |
| 274 | + "MastodonUrl": "https://mastodon.social/@luch" |
| 275 | + } |
| 276 | + ] |
| 277 | + } |
| 278 | +} |
| 279 | +``` |
0 commit comments