diff --git a/.gitea/workflows/build.yaml b/.gitea/workflows/build.yaml index fe5c0ab..84b530f 100644 --- a/.gitea/workflows/build.yaml +++ b/.gitea/workflows/build.yaml @@ -13,9 +13,7 @@ jobs: lfs: true - name: Build project. run: | - proxy - podman pull mcr.microsoft.com/dotnet/aspnet:10.0 - unproxy + podman pull mcr.azure.cn/dotnet/aspnet:10.0 cd YaeBlog pwsh build.ps1 build - name: Workaround to make sure podman-login working. diff --git a/YaeBlog.Tests/DateTimeOffsetTests.cs b/YaeBlog.Tests/DateTimeOffsetTests.cs new file mode 100644 index 0000000..f9fd8db --- /dev/null +++ b/YaeBlog.Tests/DateTimeOffsetTests.cs @@ -0,0 +1,13 @@ +namespace YaeBlog.Tests; + +public class DateTimeOffsetTests +{ + [Fact] + public void DateTimeOffsetParseTest() + { + const string input = "2026-01-04T16:36:36.5629759+08:00"; + DateTimeOffset time = DateTimeOffset.Parse(input); + + Assert.Equal("2026年01月04日 16:36:36", time.ToString("yyyy年MM月dd日 HH:mm:ss")); + } +} diff --git a/YaeBlog.Tests/YaeBlog.Tests.csproj b/YaeBlog.Tests/YaeBlog.Tests.csproj new file mode 100644 index 0000000..5d5e7c6 --- /dev/null +++ b/YaeBlog.Tests/YaeBlog.Tests.csproj @@ -0,0 +1,25 @@ + + + + net10.0 + enable + enable + false + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/YaeBlog.slnx b/YaeBlog.slnx index 53e014e..4cf5583 100644 --- a/YaeBlog.slnx +++ b/YaeBlog.slnx @@ -10,5 +10,6 @@ + diff --git a/YaeBlog/Components/Pages/Essays.razor b/YaeBlog/Components/Pages/Essays.razor index 37fa6fe..9aa0a94 100644 --- a/YaeBlog/Components/Pages/Essays.razor +++ b/YaeBlog/Components/Pages/Essays.razor @@ -12,52 +12,42 @@
-

@(_essay!.Title)

-
-
-
+
+
+

@(_essay!.Title)

+
-
-
- @foreach (string tag in _essay!.Tags) +
+ @foreach (string tag in _essay!.Tags) + { + + } +
+ +
+ 发布于: @(_essay.PublishTime.ToString("yyyy年MM月dd日 HH:mm:ss")) +
+ + @if (_essay.UpdateTime != _essay.PublishTime) { -
- - # @(tag) - +
+ 更新于: @(_essay.UpdateTime.ToString("yyyy年MM月dd日 HH:mm:ss"))
} -
-
- 发布于: @(_essay.PublishTime.ToString("yyyy年MM月dd日 hh:mm:ss")) -
- - @if (_essay.UpdateTime != _essay.PublishTime) - {
- 更新于: @(_essay.UpdateTime.ToString("yyyy年MM月dd日 hh:mm:ss")) + 总字数:@(_essay!.WordCount)字,预计阅读时间 @(_essay!.ReadTime)
- } - -
- 总字数:@(_essay!.WordCount)字,预计阅读时间 @(_essay!.ReadTime)。
-
-
- @((MarkupString)_essay!.HtmlContent) -
- -
- -
-
-
-
+

文章目录

@@ -98,8 +88,17 @@ }
-
+
+
+ @((MarkupString)_essay!.HtmlContent) +
+ +
+ +
+
+
@code { diff --git a/YaeBlog/Dockerfile b/YaeBlog/Dockerfile index 933638a..021e1d0 100644 --- a/YaeBlog/Dockerfile +++ b/YaeBlog/Dockerfile @@ -1,4 +1,4 @@ -FROM mcr.microsoft.com/dotnet/aspnet:10.0 +FROM mcr.azure.cn/dotnet/aspnet:10.0 ARG COMMIT_ID ENV COMMIT_ID=${COMMIT_ID} diff --git a/YaeBlog/Services/MarkdownWordCounter.cs b/YaeBlog/Services/MarkdownWordCounter.cs new file mode 100644 index 0000000..b5d3a84 --- /dev/null +++ b/YaeBlog/Services/MarkdownWordCounter.cs @@ -0,0 +1,62 @@ +using YaeBlog.Extensions; +using YaeBlog.Models; + +namespace YaeBlog.Services +{ + public class MarkdownWordCounter + { + private bool _inCodeBlock; + private int _index; + private readonly string _content; + + private uint WordCount { get; set; } + + private MarkdownWordCounter(BlogContent content) + { + _content = content.Content; + } + + private void CountWordInner() + { + while (_index < _content.Length) + { + if (IsCodeBlockTag()) + { + _inCodeBlock = !_inCodeBlock; + } + + if (!_inCodeBlock && char.IsLetterOrDigit(_content, _index)) + { + WordCount += 1; + } + + _index++; + } + } + + private bool IsCodeBlockTag() + { + // 首先考虑识别代码块 + bool outerCodeBlock = + Enumerable.Range(0, 3) + .Select(i => _index + i < _content.Length && _content.AsSpan().Slice(_index + i, 1) is "`") + .All(i => i); + + if (outerCodeBlock) + { + return true; + } + + // 然后识别行内代码 + return _index < _content.Length && _content.AsSpan().Slice(_index, 1) is "`"; + } + + public static uint CountWord(BlogContent content) + { + MarkdownWordCounter counter = new(content); + counter.CountWordInner(); + + return counter.WordCount; + } + } +} diff --git a/YaeBlog/Services/RendererService.cs b/YaeBlog/Services/RendererService.cs index 8317314..7069a10 100644 --- a/YaeBlog/Services/RendererService.cs +++ b/YaeBlog/Services/RendererService.cs @@ -38,7 +38,7 @@ public partial class RendererService( List essays = []; foreach (BlogContent content in preProcessedContents) { - uint wordCount = GetWordCount(content); + (uint wordCount, string readTime) = GetWordCount(content); BlogEssay essay = new() { Title = content.Metadata.Title ?? content.BlogName, @@ -46,7 +46,7 @@ public partial class RendererService( IsDraft = content.IsDraft, Description = GetDescription(content), WordCount = wordCount, - ReadTime = CalculateReadTime(wordCount), + ReadTime = readTime, PublishTime = content.Metadata.Date == default ? DateTimeOffset.Now : content.Metadata.Date, // 如果不存在最后的更新时间,就把更新时间设置为发布时间 UpdateTime = @@ -190,23 +190,16 @@ public partial class RendererService( return description; } - private uint GetWordCount(BlogContent content) + private (uint, string) GetWordCount(BlogContent content) { - int count = (from c in content.Content - where char.IsLetterOrDigit(c) - select c).Count(); + uint count = MarkdownWordCounter.CountWord(content); logger.LogDebug("Word count of {blog} is {count}", content.BlogName, count); - return (uint)count; - } - - private static string CalculateReadTime(uint wordCount) - { // 据说语文教学大纲规定,中国高中生阅读现代文的速度是600字每分钟 - int second = (int)wordCount / 10; - TimeSpan span = new(0, 0, second); + uint second = count / 10; + TimeSpan span = new(0, 0, (int)second); - return span.ToString("mm'分 'ss'秒'"); + return (count, span.ToString("mm'分'ss'秒'")); } } diff --git a/YaeBlog/build.ps1 b/YaeBlog/build.ps1 index 0242036..088c7f0 100755 --- a/YaeBlog/build.ps1 +++ b/YaeBlog/build.ps1 @@ -3,7 +3,7 @@ [cmdletbinding()] param( [Parameter(Mandatory = $true, Position = 0, HelpMessage = "Specify the build target")] - [ValidateSet("tailwind", "watch", "publish", "compress", "build")] + [ValidateSet("tailwind", "watch", "publish", "compress", "build", "dev")] [string]$Target, [string]$Output = "wwwroot", [string]$Essay, @@ -56,6 +56,28 @@ process { podman build . -t ccr.ccs.tencentyun.com/jackfiled/blog --build-arg COMMIT_ID=$commitId } + function Start-Develop { + Write-Host "Start tailwindcss and dotnet watch servers..." + $pnpmProcess = Start-Process pnpm "tailwindcss -i wwwroot/tailwind.css -o obj/Debug/net10.0/ClientAssets/tailwind.g.css -w" ` + -PassThru + + try + { + Write-Host "Started pnpm process exit? " $pnpmProcess.HasExited + Start-Process dotnet "watch -- serve" -PassThru | Wait-Process + } + finally + { + if ($pnpmProcess.HasExited) + { + Write-Error "pnpm process has exited!" + exit 1 + } + Write-Host "Kill tailwindcss and dotnet watch servers..." + $pnpmProcess | Stop-Process + } + } + switch ($Target) { "tailwind" { @@ -85,6 +107,10 @@ process { Build-Image break } + "dev" { + Start-Develop + break + } } }