Skip to content

Commit e3cebd8

Browse files
committed
feat: Add Short Codes
1 parent bfb8fbf commit e3cebd8

File tree

24 files changed

+498
-19
lines changed

24 files changed

+498
-19
lines changed

Directory.Packages.props

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,19 +11,19 @@
1111
<PackageVersion Include="Microsoft.EntityFrameworkCore.Sqlite" Version="9.0.0-rc.2.24474.1" />
1212
<PackageVersion Include="Microsoft.EntityFrameworkCore.SqlServer" Version="9.0.0-rc.2.24474.1" />
1313
<PackageVersion Include="Microsoft.Extensions.Diagnostics.HealthChecks.Abstractions" Version="9.0.0-rc.2.24474.3" />
14-
<PackageVersion Include="MongoDB.Driver" Version="2.29.0" />
15-
<PackageVersion Include="MySql.EntityFrameworkCore" Version="8.0.5" />
14+
<PackageVersion Include="MongoDB.Driver" Version="2.30.0" />
15+
<PackageVersion Include="MySql.EntityFrameworkCore" Version="9.0.0-preview" />
1616
<PackageVersion Include="RavenDB.Client" Version="6.2.0" />
1717
</ItemGroup>
1818
<ItemGroup Label="Web">
1919
<PackageVersion Include="AspNetCore.HealthChecks.UI.Client" Version="8.0.1" />
2020
<PackageVersion Include="Blazored.Toast" Version="4.2.1" />
21-
<PackageVersion Include="Blazorise.Bootstrap5" Version="1.6.1" />
22-
<PackageVersion Include="Blazorise.Markdown" Version="1.6.1" />
21+
<PackageVersion Include="Blazorise.Bootstrap5" Version="1.6.2" />
22+
<PackageVersion Include="Blazorise.Markdown" Version="1.6.2" />
2323
<PackageVersion Include="Markdig" Version="0.37.0" />
2424
<PackageVersion Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="9.0.0-rc.2.24474.3" />
2525
<PackageVersion Include="Microsoft.Extensions.Options" Version="9.0.0-rc.2.24473.5" />
26-
<PackageVersion Include="NCronJob" Version="3.0.3" />
26+
<PackageVersion Include="NCronJob" Version="3.1.2-preview" />
2727
<PackageVersion Include="System.ServiceModel.Syndication" Version="9.0.0-rc.2.24473.5" />
2828
</ItemGroup>
2929
<ItemGroup Label="Tests">
@@ -38,6 +38,6 @@
3838
<PackageVersion Include="coverlet.collector" Version="6.0.2" />
3939
<PackageVersion Include="coverlet.msbuild" Version="6.0.2" />
4040
<PackageVersion Include="xunit.v3" Version="0.4.0-pre.20" />
41-
<PackageVersion Include="xunit.runner.visualstudio" Version="3.0.0-pre.35" />
41+
<PackageVersion Include="xunit.runner.visualstudio" Version="3.0.0-pre.35" />
4242
</ItemGroup>
43-
</Project>
43+
</Project>

MIGRATION.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,21 @@
22
This document describes the changes that need to be made to migrate from one version of the blog to another.
33

44
## 8.0 to 9.0
5+
6+
### Shortcodes
7+
Shortcodes, a form a templating that can be adjusted dynamically, are introduced in this version. The following table has to be added to the database:
8+
9+
```sql
10+
CREATE TABLE Shortcodes
11+
(
12+
Id [NVARCHAR](450)] NOT NULL,
13+
Name [NVARCHAR(512)] NOT NULL,
14+
MarkdownContent NVARCHAR(MAX) NOT NULL,
15+
)
16+
```
17+
18+
### Similiar blog posts
19+
520
A new `SimilarBlogPost` table is introduced to store similar blog posts.
621

722
```sql

Readme.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ This also includes source code snippets. Highlighting is done via [highlight.js]
2121
- [Comments](./docs/Comments/Readme.md)
2222
- [Storage Provider](./docs/Storage/Readme.md)
2323
- [Search Engine Optimization (SEO)](./docs/SEO/Readme.md)
24+
- [Advanced Features](.docs/Features/AdvancedFeatures.md)
2425

2526
## Installation
2627

docs/Features/AdvancedFeatures.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
## Advanced Features
2+
3+
This page lists some of the more advanced or less-used features of the blog software.
4+
5+
### Shortcodes
6+
Shortcodes are markdown content that can be shown inside blog posts (like templates that can be referenced).
7+
The idea is to reuse certain shortcodes across various blog posts.
8+
If you update the shortcode, it will be updated across all those blog posts as well.
9+
10+
For example if you have a running promotion you can add a shortcode and link it in various blog posts. Updating the shortcode (for example that it is almost sold out) will update all blog posts that reference this shortcode.
11+
12+
#### Creating a shortcode
13+
14+
To create a shortcode, click on "Shortcodes" in the Admin tab of the navigation bar. You can create a shortcode by adding a name in the top row and the markdown content in the editor. Clicking on an already existing shortcode will allow you to either edit the shortcode or delete it.
15+
16+
Currently, deleting a shortcode will leave the shortcode name inside the blogpost. Therefore only delete shortcodes if you are sure that they are not used anymore.
17+
18+
#### Using a shortcode
19+
There are two ways:
20+
1. If you know the shortcode name, just type in `[[SHORTCODENAME]]` where `SHORTCODENAME` is the name you gave the shortcode.
21+
2. Click on the more button in the editor and select "Shortcodes". This will open a dialog where you can select the shortcode you want to insert and puts it into the clipboard.
22+
23+
### Limitations
24+
Shortcodes
25+
* are not recursive. This means that you cannot use a shortcode inside a shortcode.
26+
* are not part of the table of contents even though they might have headers.
27+
* are not part of the reading time calculation.
28+
* are only available in the content section of a blog post and not the description.
29+
* are currently only copied to the clipboard and not inserted directly into the editor at the cursor position.
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
using System;
2+
3+
namespace LinkDotNet.Blog.Domain;
4+
5+
public class ShortCode : Entity
6+
{
7+
private ShortCode(string name, string markdownContent)
8+
{
9+
Name = name;
10+
MarkdownContent = markdownContent;
11+
}
12+
13+
public string MarkdownContent { get; private set; }
14+
15+
public string Name { get; set; }
16+
17+
public void Update(string name, string content)
18+
{
19+
ArgumentException.ThrowIfNullOrWhiteSpace(name);
20+
MarkdownContent = content;
21+
Name = name;
22+
}
23+
24+
public static ShortCode Create(string name, string content)
25+
{
26+
return new ShortCode(name, content);
27+
}
28+
}

src/LinkDotNet.Blog.Infrastructure/Persistence/Sql/BlogDbContext.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ public BlogDbContext(DbContextOptions options)
2626

2727
public DbSet<SimilarBlogPost> SimilarBlogPosts { get; set; }
2828

29+
public DbSet<ShortCode> ShortCodes { get; set; }
30+
2931
protected override void OnModelCreating(ModelBuilder modelBuilder)
3032
{
3133
ArgumentNullException.ThrowIfNull(modelBuilder);
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
using LinkDotNet.Blog.Domain;
2+
using Microsoft.EntityFrameworkCore;
3+
using Microsoft.EntityFrameworkCore.Metadata.Builders;
4+
5+
namespace LinkDotNet.Blog.Infrastructure.Persistence.Sql.Mapping;
6+
7+
internal sealed class ShortCodeConfiguration : IEntityTypeConfiguration<ShortCode>
8+
{
9+
public void Configure(EntityTypeBuilder<ShortCode> builder)
10+
{
11+
builder.HasKey(s => s.Id);
12+
builder.Property(s => s.Id)
13+
.IsUnicode(false)
14+
.ValueGeneratedOnAdd();
15+
builder.Property(s => s.Name)
16+
.IsRequired()
17+
.HasMaxLength(512);
18+
builder.Property(s => s.MarkdownContent)
19+
.IsRequired();
20+
}
21+
}

src/LinkDotNet.Blog.Web/Features/AboutMe/Components/Talk/AddTalkEntryDialog.razor

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
</div>
2020
<div class="mb-3">
2121
<label for="talk-content">Description</label>
22-
<MarkdownTextArea id="talk-content" class="form-control" Rows="10"
22+
<MarkdownTextArea id="talk-content" Class="form-control" Rows="10"
2323
@bind-Value="@model.Description"></MarkdownTextArea>
2424
</div>
2525
<button id="talk-submit" class="btn btn-primary" type="submit">Submit</button>

src/LinkDotNet.Blog.Web/Features/Admin/BlogPostEditor/Components/CreateNewBlogPost.razor

Lines changed: 50 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
@using LinkDotNet.Blog.Domain
2+
@using LinkDotNet.Blog.Infrastructure
3+
@using LinkDotNet.Blog.Infrastructure.Persistence
24
@using LinkDotNet.Blog.Web.Features.Services
35
@using NCronJob
46
@inject IJSRuntime JSRuntime
57
@inject ICacheInvalidator CacheInvalidator
68
@inject IInstantJobRegistry InstantJobRegistry
9+
@inject IRepository<ShortCode> ShortCodeRepository
710

811
<div class="container">
912
<h3 class="fw-bold">@Title</h3>
@@ -17,13 +20,33 @@
1720
</div>
1821
<div class="form-floating mb-3">
1922
<MarkdownTextArea Id="short" Class="form-control" Rows="4" Placeholder="Short Description"
20-
@bind-Value="@model.ShortDescription"></MarkdownTextArea>
23+
@bind-Value="@model.ShortDescription"
24+
PreviewFunction="ReplaceShortCodes"
25+
></MarkdownTextArea>
2126
<ValidationMessage For="() => model.ShortDescription"></ValidationMessage>
2227
</div>
23-
<div class="form-floating mb-3">
28+
<div class="form-floating mb-3 relative">
2429
<MarkdownTextArea Id="content" Class="form-control" Rows="20" Placeholder="Content"
30+
PreviewFunction="ReplaceShortCodes"
2531
@bind-Value="@model.Content"></MarkdownTextArea>
2632
<ValidationMessage For="() => model.Content"></ValidationMessage>
33+
34+
<div class="btn-group position-absolute bottom-0 end-0 m-5 extra-buttons">
35+
<button class="btn btn-primary btn-outlined btn-sm dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
36+
More
37+
</button>
38+
<ul class="dropdown-menu">
39+
@if (shortCodes.Count > 0)
40+
{
41+
<li>
42+
<button type="button" @onclick="OpenShortCodeDialog" class="dropdown-item">
43+
<span>Get shortcode</span>
44+
</button>
45+
</li>
46+
}
47+
<li><button type="button" class="dropdown-item" @onclick="FeatureDialog.Open">Experimental Features</button></li>
48+
</ul>
49+
</div>
2750
</div>
2851
<div class="form-floating mb-3">
2952
<InputText type="url" class="form-control" id="preview" placeholder="Preview-Url" @bind-Value="model.PreviewImageUrl"/>
@@ -83,6 +106,7 @@
83106
</div>
84107

85108
<FeatureInfoDialog @ref="FeatureDialog"></FeatureInfoDialog>
109+
<ShortCodeDialog @ref="ShortCodeDialog" ShortCodes="shortCodes"></ShortCodeDialog>
86110

87111
<NavigationLock ConfirmExternalNavigation="@model.IsDirty" OnBeforeInternalNavigation="PreventNavigationWhenDirty"></NavigationLock>
88112
@code {
@@ -99,14 +123,21 @@
99123
public bool ClearAfterCreated { get; set; } = true;
100124

101125
private FeatureInfoDialog FeatureDialog { get; set; } = default!;
126+
private ShortCodeDialog ShortCodeDialog { get; set; } = default!;
102127

103128
private CreateNewModel model = new();
104129

105130
private bool canSubmit = true;
131+
private IPagedList<ShortCode> shortCodes = PagedList<ShortCode>.Empty;
106132

107133
private bool IsScheduled => model.ScheduledPublishDate.HasValue;
108134

109-
protected override void OnParametersSet()
135+
protected override async Task OnInitializedAsync()
136+
{
137+
shortCodes = await ShortCodeRepository.GetAllAsync();
138+
}
139+
140+
protected override void OnParametersSet()
110141
{
111142
if (BlogPost is null)
112143
{
@@ -161,4 +192,20 @@
161192
context.PreventNavigation();
162193
}
163194
}
195+
196+
private Task<string> ReplaceShortCodes(string markdown)
197+
{
198+
foreach (var code in shortCodes)
199+
{
200+
markdown = markdown.Replace($"[[{code.Name}]]", code.MarkdownContent);
201+
}
202+
203+
return Task.FromResult(MarkdownConverter.ToMarkupString(markdown).Value);
204+
}
205+
206+
private void OpenShortCodeDialog()
207+
{
208+
ShortCodeDialog.Open();
209+
StateHasChanged();
210+
}
164211
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
.extra-buttons {
2+
opacity: 0.25;
3+
}
4+
5+
.extra-buttons:hover {
6+
opacity: 1;
7+
}

0 commit comments

Comments
 (0)