Compare commits
3 Commits
feat/intro
...
c446012199
| Author | SHA1 | Date | |
|---|---|---|---|
|
c446012199
|
|||
|
3053b83bbf
|
|||
|
457316971c
|
@@ -15,9 +15,6 @@ trim_trailing_whitespace = true
|
|||||||
[project.json]
|
[project.json]
|
||||||
indent_size = 2
|
indent_size = 2
|
||||||
|
|
||||||
[*.{yaml,yml}]
|
|
||||||
indent_size = 2
|
|
||||||
|
|
||||||
# C# and Visual Basic files
|
# C# and Visual Basic files
|
||||||
[*.{cs,vb}]
|
[*.{cs,vb}]
|
||||||
charset = utf-8-bom
|
charset = utf-8-bom
|
||||||
|
|||||||
@@ -1,30 +1,33 @@
|
|||||||
name: Build blog docker image
|
name: Build blog docker image
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- master
|
- master
|
||||||
jobs:
|
jobs:
|
||||||
Build-Blog-Image:
|
Build-Blog-Image:
|
||||||
runs-on: archlinux
|
runs-on: archlinux
|
||||||
steps:
|
steps:
|
||||||
- name: Check out code.
|
- uses: https://mirrors.rrricardo.top/actions/checkout.git@v4
|
||||||
uses: https://mirrors.rrricardo.top/actions/checkout.git@v4
|
name: Check out code
|
||||||
with:
|
with:
|
||||||
lfs: true
|
lfs: true
|
||||||
- name: Build project.
|
- name: Build project
|
||||||
run: |
|
run: |
|
||||||
podman pull mcr.azure.cn/dotnet/aspnet:10.0
|
cd YaeBlog
|
||||||
cd YaeBlog
|
dotnet publish
|
||||||
pwsh build.ps1 build
|
- name: Build docker image
|
||||||
- name: Workaround to make sure podman-login working.
|
run: |
|
||||||
run: |
|
cd YaeBlog
|
||||||
mkdir /root/.docker
|
podman build . -t registry.cn-beijing.aliyuncs.com/jackfiled/blog:latest --build-arg COMMIT_ID=$(git rev-parse --short=10 HEAD)
|
||||||
- name: Login tencent cloud docker registry.
|
- name: Workaround to make sure podman login succeed
|
||||||
uses: https://mirrors.rrricardo.top/actions/podman-login.git@v1
|
run: |
|
||||||
with:
|
mkdir /root/.docker
|
||||||
registry: ccr.ccs.tencentyun.com
|
- name: Login aliyun docker registry
|
||||||
username: 100044380877
|
uses: https://mirrors.rrricardo.top/actions/podman-login.git@v1
|
||||||
password: ${{ secrets.TENCENT_REGISTRY_PASSWORD }}
|
with:
|
||||||
auth_file_path: /etc/containers/auth.json
|
registry: registry.cn-beijing.aliyuncs.com
|
||||||
- name: Push docker image.
|
username: 初冬的朝阳
|
||||||
run: podman push ccr.ccs.tencentyun.com/jackfiled/blog:latest
|
password: ${{ secrets.ALIYUN_PASSWORD }}
|
||||||
|
auth_file_path: /etc/containers/auth.json
|
||||||
|
- name: Push docker image
|
||||||
|
run: podman push registry.cn-beijing.aliyuncs.com/jackfiled/blog:latest
|
||||||
|
|||||||
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -1,3 +0,0 @@
|
|||||||
[submodule "third-party/BlazorSvgComponents"]
|
|
||||||
path = third-party/BlazorSvgComponents
|
|
||||||
url = https://git.rrricardo.top/jackfiled/BlazorSvgComponents.git
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
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"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<TargetFramework>net10.0</TargetFramework>
|
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
|
||||||
<Nullable>enable</Nullable>
|
|
||||||
<IsPackable>false</IsPackable>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="coverlet.collector" Version="6.0.4" />
|
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
|
|
||||||
<PackageReference Include="xunit" Version="2.9.3" />
|
|
||||||
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.4" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<Using Include="Xunit" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<ProjectReference Include="..\YaeBlog\YaeBlog.csproj" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
|
||||||
@@ -10,6 +10,5 @@
|
|||||||
<File Path="LICENSE" />
|
<File Path="LICENSE" />
|
||||||
<File Path="README.md" />
|
<File Path="README.md" />
|
||||||
</Folder>
|
</Folder>
|
||||||
<Project Path="YaeBlog.Tests/YaeBlog.Tests.csproj" />
|
|
||||||
<Project Path="YaeBlog/YaeBlog.csproj" />
|
<Project Path="YaeBlog/YaeBlog.csproj" />
|
||||||
</Solution>
|
</Solution>
|
||||||
|
|||||||
@@ -6,11 +6,5 @@ public interface IEssayScanService
|
|||||||
{
|
{
|
||||||
public Task<BlogContents> ScanContents();
|
public Task<BlogContents> ScanContents();
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 将对应的博客文章保存在磁盘上
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="content"></param>
|
|
||||||
/// <param name="isDraft">指定对应博客文章是否为草稿。因为BlogContent是不可变对象,因此提供该参数以方便publish的实现。</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public Task SaveBlogContent(BlogContent content, bool isDraft = true);
|
public Task SaveBlogContent(BlogContent content, bool isDraft = true);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ public sealed class YaeBlogCommand
|
|||||||
AddWatchCommand(_rootCommand);
|
AddWatchCommand(_rootCommand);
|
||||||
AddListCommand(_rootCommand);
|
AddListCommand(_rootCommand);
|
||||||
AddNewCommand(_rootCommand);
|
AddNewCommand(_rootCommand);
|
||||||
AddUpdateCommand(_rootCommand);
|
|
||||||
AddPublishCommand(_rootCommand);
|
AddPublishCommand(_rootCommand);
|
||||||
AddScanCommand(_rootCommand);
|
AddScanCommand(_rootCommand);
|
||||||
AddCompressCommand(_rootCommand);
|
AddCompressCommand(_rootCommand);
|
||||||
@@ -47,7 +46,7 @@ public sealed class YaeBlogCommand
|
|||||||
|
|
||||||
WebApplication application = builder.Build();
|
WebApplication application = builder.Build();
|
||||||
|
|
||||||
application.MapStaticAssets();
|
application.UseStaticFiles();
|
||||||
application.UseAntiforgery();
|
application.UseAntiforgery();
|
||||||
application.UseYaeBlog();
|
application.UseYaeBlog();
|
||||||
|
|
||||||
@@ -77,7 +76,7 @@ public sealed class YaeBlogCommand
|
|||||||
|
|
||||||
WebApplication application = builder.Build();
|
WebApplication application = builder.Build();
|
||||||
|
|
||||||
application.MapStaticAssets();
|
application.UseStaticFiles();
|
||||||
application.UseAntiforgery();
|
application.UseAntiforgery();
|
||||||
application.UseYaeBlog();
|
application.UseYaeBlog();
|
||||||
|
|
||||||
@@ -110,12 +109,7 @@ public sealed class YaeBlogCommand
|
|||||||
|
|
||||||
await essayScanService.SaveBlogContent(new BlogContent(
|
await essayScanService.SaveBlogContent(new BlogContent(
|
||||||
new FileInfo(Path.Combine(blogOption.Value.Root, "drafts", file + ".md")),
|
new FileInfo(Path.Combine(blogOption.Value.Root, "drafts", file + ".md")),
|
||||||
new MarkdownMetadata
|
new MarkdownMetadata { Title = file, Date = DateTime.Now },
|
||||||
{
|
|
||||||
Title = file,
|
|
||||||
Date = DateTimeOffset.Now.ToString("o"),
|
|
||||||
UpdateTime = DateTimeOffset.Now.ToString("o")
|
|
||||||
},
|
|
||||||
string.Empty, true, [], []));
|
string.Empty, true, [], []));
|
||||||
|
|
||||||
Console.WriteLine($"Created new blog '{file}.");
|
Console.WriteLine($"Created new blog '{file}.");
|
||||||
@@ -123,32 +117,6 @@ public sealed class YaeBlogCommand
|
|||||||
new EssayScanServiceBinder());
|
new EssayScanServiceBinder());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void AddUpdateCommand(RootCommand rootCommand)
|
|
||||||
{
|
|
||||||
Command newCommand = new("update", "Update the blog essay.");
|
|
||||||
rootCommand.AddCommand(newCommand);
|
|
||||||
|
|
||||||
Argument<string> filenameArgument = new(name: "blog name", description: "The blog filename to update.");
|
|
||||||
newCommand.AddArgument(filenameArgument);
|
|
||||||
|
|
||||||
newCommand.SetHandler(async (file, _, _, essayScanService) =>
|
|
||||||
{
|
|
||||||
Console.WriteLine("HINT: The update command only consider published blogs.");
|
|
||||||
BlogContents contents = await essayScanService.ScanContents();
|
|
||||||
|
|
||||||
BlogContent? content = contents.Posts.FirstOrDefault(c => c.BlogName == file);
|
|
||||||
if (content is null)
|
|
||||||
{
|
|
||||||
Console.WriteLine($"Target essay {file} is not exist.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
content.Metadata.UpdateTime = DateTimeOffset.Now.ToString("o");
|
|
||||||
await essayScanService.SaveBlogContent(content, content.IsDraft);
|
|
||||||
}, filenameArgument,
|
|
||||||
new BlogOptionsBinder(), new LoggerBinder<EssayScanService>(), new EssayScanServiceBinder());
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void AddListCommand(RootCommand rootCommand)
|
private static void AddListCommand(RootCommand rootCommand)
|
||||||
{
|
{
|
||||||
Command command = new("list", "List all blogs");
|
Command command = new("list", "List all blogs");
|
||||||
@@ -243,8 +211,7 @@ public sealed class YaeBlogCommand
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 设置发布的时间
|
// 设置发布的时间
|
||||||
content.Metadata.Date = DateTimeOffset.Now.ToString("o");
|
content.Metadata.Date = DateTime.Now;
|
||||||
content.Metadata.UpdateTime = DateTimeOffset.Now.ToString("o");
|
|
||||||
|
|
||||||
// 将选中的博客文件复制到posts
|
// 将选中的博客文件复制到posts
|
||||||
await essayScanService.SaveBlogContent(content, isDraft: false);
|
await essayScanService.SaveBlogContent(content, isDraft: false);
|
||||||
|
|||||||
@@ -3,44 +3,18 @@
|
|||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8"/>
|
<meta charset="utf-8"/>
|
||||||
<meta lang="zh-CN"/>
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||||
<base href="/"/>
|
<base href="/"/>
|
||||||
<link rel="stylesheet" href="@Assets["YaeBlog.styles.css"]"/>
|
<link rel="stylesheet" href="YaeBlog.styles.css"/>
|
||||||
<link rel="icon" href="@Assets["images/favicon.ico"]"/>
|
<link rel="icon" href="images/favicon.ico"/>
|
||||||
<link rel="stylesheet" href="@Assets["tailwind.g.css"]"/>
|
<link rel="stylesheet" href="globals.css"/>
|
||||||
<style>
|
<link rel="stylesheet" href="tailwind.g.css"/>
|
||||||
@@font-face {
|
|
||||||
font-family: "Font Awesome 7 Free";
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 400;
|
|
||||||
font-display: block;
|
|
||||||
src: url(@Assets["fonts/fa-regular-400.woff2"]) format("woff2");
|
|
||||||
}
|
|
||||||
|
|
||||||
@@font-face {
|
|
||||||
font-family: "Font Awesome 7 Free";
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 900;
|
|
||||||
font-display: block;
|
|
||||||
src: url(@Assets["fonts/fa-solid-900.woff2"]) format("woff2")
|
|
||||||
}
|
|
||||||
|
|
||||||
@@font-face {
|
|
||||||
font-family: "Font Awesome 7 Brands";
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 400;
|
|
||||||
font-display: block;
|
|
||||||
src: url(@Assets["fonts/fa-brands-400.woff2"]) format("woff2")
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<HeadOutlet/>
|
<HeadOutlet/>
|
||||||
<ImportMap/>
|
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<Routes/>
|
<Routes/>
|
||||||
<script src="@Assets["_framework/blazor.web.js"]"></script>
|
<script src="_framework/blazor.web.js"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
<div class="flex flex-col p-3">
|
<div class="flex flex-col p-3">
|
||||||
<div class="text-3xl font-bold py-2">
|
<div class="text-3xl font-bold py-2">
|
||||||
<a href="@(Essay.EssayLink)">@(Essay.Title)</a>
|
<a href="/blog/essays/@(Essay.FileName)" target="_blank">@(Essay.Title)</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="p-2 flex flex-row justify-content-start gap-2">
|
<div class="p-2 flex flex-row justify-content-start gap-2">
|
||||||
@@ -14,7 +14,9 @@
|
|||||||
@foreach (string key in Essay.Tags)
|
@foreach (string key in Essay.Tags)
|
||||||
{
|
{
|
||||||
<div class="text-sky-600">
|
<div class="text-sky-600">
|
||||||
<Anchor Address="@($"/blog/tags/?tagName={UrlEncoder.Default.Encode(key)}")" Text="@($"# {key}")"/>
|
<a href="/blog/tags/?tagName=@(UrlEncoder.Default.Encode(key))">
|
||||||
|
# @key
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<div>
|
<div>
|
||||||
<p class="text-md">
|
<p class="text-md">
|
||||||
2021 - @(DateTimeOffset.Now.Year) ©
|
2021 - @(DateTimeOffset.Now.Year) ©
|
||||||
<Anchor Address="https://rrricardot.top" Text="初冬的朝阳"/>
|
<Anchor Address="https://rrricardot.top" Text="Ricardo Ren"/>
|
||||||
,由
|
,由
|
||||||
<Anchor Address="https://dotnet.microsoft.com" Text="@DotnetVersion"/>
|
<Anchor Address="https://dotnet.microsoft.com" Text="@DotnetVersion"/>
|
||||||
驱动。
|
驱动。
|
||||||
@@ -22,9 +22,9 @@
|
|||||||
|
|
||||||
@code
|
@code
|
||||||
{
|
{
|
||||||
private static string DotnetVersion => $".NET {Environment.Version}";
|
private string DotnetVersion => $".NET {Environment.Version}";
|
||||||
|
|
||||||
private static string BuildCommitId => Environment.GetEnvironmentVariable("COMMIT_ID") ?? "local_build";
|
private string BuildCommitId => Environment.GetEnvironmentVariable("COMMIT_ID") ?? "local_build";
|
||||||
|
|
||||||
private static string BuildCommitUrl => $"https://git.rrricardo.top/jackfiled/YaeBlog/commit/{BuildCommitId}";
|
private string BuildCommitUrl => $"https://git.rrricardo.top/jackfiled/YaeBlog/commit/{BuildCommitId}";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,28 +0,0 @@
|
|||||||
@inherits LayoutComponentBase
|
|
||||||
|
|
||||||
@attribute [StreamRendering]
|
|
||||||
|
|
||||||
<main class="container mx-auto flex flex-col min-h-screen">
|
|
||||||
<div class="grid grid-cols-3 mx-3">
|
|
||||||
<div class="md:col-span-2 col-span-3 h-20 flex items-center">
|
|
||||||
<a href="/blog/">
|
|
||||||
<span class="text-blue-600 text-2xl">Ricardo's Blog</span>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="md:col-span-1 col-span-3 h-20 flex items-center">
|
|
||||||
<div class="flex flex-row w-full px-2 md:justify-center justify-end text-xl gap-3">
|
|
||||||
<Anchor Address="/blog/archives" Text="归档"/>
|
|
||||||
<Anchor Address="/blog/tags/" Text="标签"/>
|
|
||||||
<Anchor Address="/about/" Text="关于" NewPage="@(true)"/>
|
|
||||||
<Anchor Address="/friends" Text="友链" NewPage="@(true)"/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="px-4 py-2 flex-grow">
|
|
||||||
@Body
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Foonter/>
|
|
||||||
</main>
|
|
||||||
@@ -1,92 +0,0 @@
|
|||||||
@page "/about"
|
|
||||||
|
|
||||||
<PageTitle>
|
|
||||||
关于
|
|
||||||
</PageTitle>
|
|
||||||
|
|
||||||
<div class="flex flex-col">
|
|
||||||
<div>
|
|
||||||
<h1 class="text-4xl">关于</h1>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="py-4">
|
|
||||||
<span class="italic">把字刻在石头上!(・’ω’・)</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex flex-col p-2">
|
|
||||||
<div class="flex flex-col p-2">
|
|
||||||
<div class="pb-2">
|
|
||||||
<h3 class="text-2xl">关于我</h3>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mx-4">
|
|
||||||
<div class="my-4">
|
|
||||||
<p class="my-2">
|
|
||||||
正在明光村幼儿园附属研究生院攻读计算机科学与技术的硕士学位,研究AI编译器和异构编译器。
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p class="my-2">
|
|
||||||
一般在互联网上使用<span class="italic">初冬的朝阳</span>或者<span
|
|
||||||
class="italic">jackfiled</span>的名字活动。
|
|
||||||
<span class="line-through">(都是ICP备案过的人了,网名似乎没有太大的用处)</span>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="my-4">
|
|
||||||
<p class="my-1">
|
|
||||||
主要是一个C#程序员,目前也在尝试写一点Rust。
|
|
||||||
<span class="line-through">
|
|
||||||
总体上对于编程语言的态度是“大家都是我的翅膀.jpg”。
|
|
||||||
</span>
|
|
||||||
</p>
|
|
||||||
<p class="my-1">
|
|
||||||
写过一些前后端分离的项目,对于RISC-V相关的开发项目也颇感兴趣。
|
|
||||||
</p>
|
|
||||||
<p class="my-1">
|
|
||||||
常常因为现实的压力而写一些C/C++,现在就在和MLIR殊死搏斗。
|
|
||||||
</p>
|
|
||||||
<p class="my-1">
|
|
||||||
日常使用Arch Linux。
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="my-2">
|
|
||||||
<p class="my-1">
|
|
||||||
100%社恐。日常生活是宅在电脑前面自言自语。
|
|
||||||
</p>
|
|
||||||
<p class="my-1">
|
|
||||||
兴趣活动是读书和看番,目前在玩戴森球计划和三角洲。
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex flex-col p-2">
|
|
||||||
<div class="pb-2">
|
|
||||||
<h3 class="text-2xl">关于本站</h3>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mx-4">
|
|
||||||
<div class="my-4">
|
|
||||||
<p class="my-2">
|
|
||||||
本站肇始于2021年下半年,在开始的两年中个人网站和博客是分别的两个网站,个人网站是裸HTML写的,博客是用
|
|
||||||
<Anchor Text="Hexo" Address="https://hexo.io" NewPage="@(true)"/>
|
|
||||||
的。
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="my-4">
|
|
||||||
<p class="my-2">
|
|
||||||
2024年,我们决定使用.NET技术完全重构两个网站,合二为一。虽然目前这个版本还是一个半成品,但是我们一定会努力的~(确信。
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="my-4">
|
|
||||||
<p class="my-2">
|
|
||||||
2025年,我们将使用的样式库从Bootstrap迁移到Tailwind CSS,将现代的前端技术同Blazor结合起来。
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@@ -1,97 +0,0 @@
|
|||||||
@page "/"
|
|
||||||
@using YaeBlog.Abstraction
|
|
||||||
@using YaeBlog.Models
|
|
||||||
@inject IEssayContentService EssayContentInstance
|
|
||||||
|
|
||||||
<PageTitle>
|
|
||||||
Ricardo's Index
|
|
||||||
</PageTitle>
|
|
||||||
|
|
||||||
<div class="mx-14 lg:mx-20">
|
|
||||||
<div class="grid grid-cols-3 py-4 lg:mx-20">
|
|
||||||
<div class="col-span-3 md:col-span-1 lg:m-10">
|
|
||||||
<img src="@Assets["images/avatar.png"]" alt="Ricardo's Avatar"
|
|
||||||
class="h-auto max-w-full rounded-md border border-gray-400">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-span-3 md:col-span-2">
|
|
||||||
<div class="flex flex-col gap-y-3 items-center md:items-start md:px-6">
|
|
||||||
<div class="">
|
|
||||||
<div class="text-3xl font-bold">初冬的朝阳</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="">
|
|
||||||
<p class="text-lg">a.k.a jackfiled</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="">
|
|
||||||
<p class="text-lg italic">世界很大,时间很长。</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex flex-row gap-2">
|
|
||||||
<a href="https://github.com/jackfiled" target="_blank">
|
|
||||||
<div>
|
|
||||||
<span class="fa-brands fa-github text-xl"></span>
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a href="https://git.rrricardo.top/jackfiled/" target="_blank">
|
|
||||||
<div>
|
|
||||||
<span class="gitea-icon text-xl"></span>
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a href="https://space.bilibili.com/378831522" target="_blank">
|
|
||||||
<div>
|
|
||||||
<span class="fa-brands fa-bilibili text-xl"></span>
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a href="https://xhslink.com/m/5GVDzyKf3De" target="_blank">
|
|
||||||
<div>
|
|
||||||
<span class="rednote-icon text-xl"></span>
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="py-5">
|
|
||||||
<p class="text-lg">恕我不能亲自为您沏茶,还是非常欢迎您来,能在广阔的互联网世界中发现这里实属不易。</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="text-lg pt-2">
|
|
||||||
<p class="py-1">
|
|
||||||
正在攻读计算机科学与技术的硕士学位,研究方向是AI编译和异构编译!
|
|
||||||
</p>
|
|
||||||
<p class="py-1">
|
|
||||||
喜欢优雅的代码,香甜的蛋糕等等一切可爱的事物。
|
|
||||||
</p>
|
|
||||||
<p class="py-1">
|
|
||||||
<Anchor Address="/blog/" Text="个人博客"/>中收集了我的各种奇思妙想,如果感兴趣欢迎移步。
|
|
||||||
@if (_latestEssay is not null)
|
|
||||||
{
|
|
||||||
<span>
|
|
||||||
最新的一期博客关注 <Anchor Text="@(_latestEssay.Title)" Address="@(_latestEssay.EssayLink)"/>。
|
|
||||||
</span>
|
|
||||||
}
|
|
||||||
</p>
|
|
||||||
<p class="py-1">
|
|
||||||
日常的代码开发使用自建的<Anchor Text="Gitea" Address="https://git.rrricardo.top" NewPage="@(true)"/>进行,个人
|
|
||||||
开发的各种项目都可以在上面找到。
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
@code {
|
|
||||||
private BlogEssay? _latestEssay;
|
|
||||||
|
|
||||||
protected override void OnInitialized()
|
|
||||||
{
|
|
||||||
base.OnInitialized();
|
|
||||||
_latestEssay = EssayContentInstance.Essays.OrderByDescending(e => e.UpdateTime).FirstOrDefault();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
.fa-brands {
|
|
||||||
font-family: "Font Awesome 7 Brands", "Font Awesome 7 Free";
|
|
||||||
font-style: normal;
|
|
||||||
font-synthesis: none;
|
|
||||||
font-variant: normal;
|
|
||||||
line-height: 1;
|
|
||||||
text-rendering: auto;
|
|
||||||
font-weight: 400;
|
|
||||||
}
|
|
||||||
|
|
||||||
.fa-github::before {
|
|
||||||
content: "\f09b";
|
|
||||||
color: #24292e;
|
|
||||||
}
|
|
||||||
|
|
||||||
.fa-bilibili::before {
|
|
||||||
content: "\e3d9";
|
|
||||||
color: #00AEEC;
|
|
||||||
}
|
|
||||||
|
|
||||||
.gitea-icon {
|
|
||||||
display: inline-block;
|
|
||||||
vertical-align: -0.125em;
|
|
||||||
width: 1em;
|
|
||||||
height: 1em;
|
|
||||||
|
|
||||||
background-image: url("https://docs.gitea.com/img/gitea.svg");
|
|
||||||
background-size: contain;
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
background-position: center;
|
|
||||||
|
|
||||||
user-select: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.rednote-icon {
|
|
||||||
display: inline-block;
|
|
||||||
vertical-align: -0.125em;
|
|
||||||
width: 1em;
|
|
||||||
height: 1em;
|
|
||||||
|
|
||||||
background-image: url("images/xiaohongshu-seeklogo.svg");
|
|
||||||
background-size: contain;
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
background-position: center;
|
|
||||||
|
|
||||||
user-select: none;
|
|
||||||
}
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
<Project>
|
|
||||||
<PropertyGroup>
|
|
||||||
<ClientAssetsRestoreCommand Condition="'$(ClientAssesRestoreCommand)' == ''">pnpm install</ClientAssetsRestoreCommand>
|
|
||||||
<ClientAssetsBuildCommand Condition="'$(ClientAssetsBuildCommand)' == ''">pnpm run build</ClientAssetsBuildCommand>
|
|
||||||
<ClientAssetsBuildOutputParameter Condition="'$(ClientAssetsBuildOutputParameter)' == ''">--output</ClientAssetsBuildOutputParameter>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<_RestoreClientAssetsBeforeTargets Condition="'$(TargetFramework)' == ''">DispatchToInnerBuilds</_RestoreClientAssetsBeforeTargets>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<Target Name="RestoreClientAssets" BeforeTargets="$(_RestoreClientAssetsBeforeTargets)">
|
|
||||||
<Message Importance="high" Text="Running $(ClientAssetsRestoreCommand)"/>
|
|
||||||
<Exec Command="$(ClientAssetsRestoreCommand)"/>
|
|
||||||
</Target>
|
|
||||||
|
|
||||||
<Target Name="BuildClientAssets" DependsOnTargets="RestoreClientAssets" BeforeTargets="AssignTargetPaths">
|
|
||||||
<PropertyGroup>
|
|
||||||
<_ClientAssetsOutputFullPath>$([System.IO.Path]::GetFullPath('$(IntermediateOutputPath)ClientAssets'))</_ClientAssetsOutputFullPath>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<MakeDir Directories="$(_ClientAssetsOutputFullPath)"/>
|
|
||||||
<Exec Command="$(ClientAssetsBuildCommand) $(ClientAssetsBuildOutputParameter) $(_ClientAssetsOutputFullPath)"/>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<_ClientAssetsBuildOutput Include="$(IntermediateOutputPath)ClientAssets\**"/>
|
|
||||||
</ItemGroup>
|
|
||||||
</Target>
|
|
||||||
|
|
||||||
<Target Name="DefineClientAssets" AfterTargets="BuildClientAssets" DependsOnTargets="ResolveStaticWebAssetsConfiguration">
|
|
||||||
<ItemGroup>
|
|
||||||
<FileWrites Include="@(_ClientAssetsBuildOutput)"/>
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<DefineStaticWebAssets
|
|
||||||
CandidateAssets="@(_ClientAssetsBuildOutput)"
|
|
||||||
SourceId="$(PackageId)"
|
|
||||||
SourceType="Computed"
|
|
||||||
ContentRoot="$(_ClientAssetsOutputFullPath)"
|
|
||||||
BasePath="$(StaticWebAssetBasePath)"
|
|
||||||
>
|
|
||||||
<Output TaskParameter="Assets" ItemName="StaticWebAsset"/>
|
|
||||||
<Output TaskParameter="Assets" ItemName="_ClientAssetsStaticWebAsset"/>
|
|
||||||
</DefineStaticWebAssets>
|
|
||||||
|
|
||||||
<DefineStaticWebAssetEndpoints
|
|
||||||
CandidateAssets="@(_ClientAssetsStaticWebAsset)"
|
|
||||||
ContentTypeMappings="@(StaticWebAssetContentTypeMapping)"
|
|
||||||
>
|
|
||||||
<Output TaskParameter="Endpoints" ItemName="StaticWebAssetEndpoint" />
|
|
||||||
</DefineStaticWebAssetEndpoints>
|
|
||||||
</Target>
|
|
||||||
</Project>
|
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
FROM mcr.azure.cn/dotnet/aspnet:10.0
|
FROM mcr.microsoft.com/dotnet/aspnet:9.0
|
||||||
|
|
||||||
ARG COMMIT_ID
|
ARG COMMIT_ID
|
||||||
ENV COMMIT_ID=${COMMIT_ID}
|
ENV COMMIT_ID=${COMMIT_ID}
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY bin/Release/net10.0/publish/ ./
|
COPY bin/Release/net9.0/publish/ ./
|
||||||
COPY source/ ./source/
|
COPY source/ ./source/
|
||||||
COPY appsettings.json .
|
COPY appsettings.json .
|
||||||
|
|
||||||
|
|||||||
44
YaeBlog/Layout/BlogLayout.razor
Normal file
44
YaeBlog/Layout/BlogLayout.razor
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
@inherits LayoutComponentBase
|
||||||
|
|
||||||
|
@attribute [StreamRendering]
|
||||||
|
|
||||||
|
<main class="container mx-auto flex flex-col min-h-screen">
|
||||||
|
<div class="grid grid-cols-3 mx-3">
|
||||||
|
<div class="md:col-span-2 col-span-3 h-20 flex items-center">
|
||||||
|
<a href="/blog/">
|
||||||
|
<span class="text-blue-600 text-2xl">Ricardo's Blog</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="md:col-span-1 col-span-3 h-20 flex items-center">
|
||||||
|
<div class="flex flex-row w-full px-2 gap-3 md:justify-center justify-end">
|
||||||
|
<div>
|
||||||
|
<a href="/blog/archives/">
|
||||||
|
<span class="text-xl text-blue-600">归档</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<a href="/blog/tags/">
|
||||||
|
<span class="text-xl text-blue-600">标签</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<a href="/about/" target="_blank">
|
||||||
|
<span class="text-xl text-blue-600">关于</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<a href="/friends/" target="_blank">
|
||||||
|
<span class="text-xl text-blue-600">友链</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="px-4 py-2 flex-grow">
|
||||||
|
@Body
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Foonter/>
|
||||||
|
</main>
|
||||||
@@ -17,11 +17,13 @@
|
|||||||
|
|
||||||
<Anchor
|
<Anchor
|
||||||
Address="/about/"
|
Address="/about/"
|
||||||
Text="关于"/>
|
Text="关于"
|
||||||
|
NewPage="@(true)"/>
|
||||||
|
|
||||||
<Anchor
|
<Anchor
|
||||||
Address="/friends"
|
Address="/friends"
|
||||||
Text="友链"/>
|
Text="友链"
|
||||||
|
NewPage="@(true)"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -8,9 +8,7 @@ public class BlogEssay : IComparable<BlogEssay>
|
|||||||
|
|
||||||
public required bool IsDraft { get; init; }
|
public required bool IsDraft { get; init; }
|
||||||
|
|
||||||
public required DateTimeOffset PublishTime { get; init; }
|
public required DateTime PublishTime { get; init; }
|
||||||
|
|
||||||
public required DateTimeOffset UpdateTime { get; init; }
|
|
||||||
|
|
||||||
public required string Description { get; init; }
|
public required string Description { get; init; }
|
||||||
|
|
||||||
@@ -22,8 +20,6 @@ public class BlogEssay : IComparable<BlogEssay>
|
|||||||
|
|
||||||
public required string HtmlContent { get; init; }
|
public required string HtmlContent { get; init; }
|
||||||
|
|
||||||
public string EssayLink => $"/blog/essays/{FileName}";
|
|
||||||
|
|
||||||
public BlogEssay WithNewHtmlContent(string newHtmlContent)
|
public BlogEssay WithNewHtmlContent(string newHtmlContent)
|
||||||
{
|
{
|
||||||
var essay = new BlogEssay
|
var essay = new BlogEssay
|
||||||
@@ -32,7 +28,6 @@ public class BlogEssay : IComparable<BlogEssay>
|
|||||||
FileName = FileName,
|
FileName = FileName,
|
||||||
IsDraft = IsDraft,
|
IsDraft = IsDraft,
|
||||||
PublishTime = PublishTime,
|
PublishTime = PublishTime,
|
||||||
UpdateTime = UpdateTime,
|
|
||||||
Description = Description,
|
Description = Description,
|
||||||
WordCount = WordCount,
|
WordCount = WordCount,
|
||||||
ReadTime = ReadTime,
|
ReadTime = ReadTime,
|
||||||
|
|||||||
@@ -4,9 +4,7 @@ public class MarkdownMetadata
|
|||||||
{
|
{
|
||||||
public string? Title { get; set; }
|
public string? Title { get; set; }
|
||||||
|
|
||||||
public string? Date { get; set; }
|
public DateTime? Date { get; set; }
|
||||||
|
|
||||||
public string? UpdateTime { get; set; }
|
|
||||||
|
|
||||||
public List<string>? Tags { get; set; }
|
public List<string>? Tags { get; set; }
|
||||||
}
|
}
|
||||||
|
|||||||
79
YaeBlog/Pages/About.razor
Normal file
79
YaeBlog/Pages/About.razor
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
@page "/about"
|
||||||
|
|
||||||
|
<PageTitle>
|
||||||
|
关于
|
||||||
|
</PageTitle>
|
||||||
|
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<div>
|
||||||
|
<h1 class="text-4xl">关于</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="py-4">
|
||||||
|
<span class="italic">把字刻在石头上!(・’ω’・)</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-col p-2">
|
||||||
|
<div class="flex flex-col p-2">
|
||||||
|
<div class="pb-2">
|
||||||
|
<h3 class="text-2xl">关于我</h3>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="py-2">
|
||||||
|
计算机科学与技术在读大学生,明光村幼儿园附属大学所属。正处于读书和失业的叠加态。
|
||||||
|
一般在互联网上使用<span class="italic">初冬的朝阳</span>或者<span class="italic">jackfiled</span>的名字活动。
|
||||||
|
<span class="line-through">都是ICP备案过的人了,网名似乎没有太大的用处(</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="py-2">
|
||||||
|
主要是一个C#程序员,目前也在尝试写一点Rust。
|
||||||
|
总体上对于编程语言的态度是“<span>大家都是我的翅膀.jpg</span>”。
|
||||||
|
前后端分离的项目本当上手。
|
||||||
|
常常因为现实的压力而写一些C/C++。
|
||||||
|
<span class="line-through">对于Java和Go的评价很低。</span>
|
||||||
|
日常使用ArchLinux。
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="py-2">
|
||||||
|
100%社恐。日常生活是宅在电脑前面自言自语。
|
||||||
|
兴趣活动是读书和看番,目前在玩原神和三角洲。
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="py-4">
|
||||||
|
常常被人批评没有梦想,这里就随便瞎编一下。
|
||||||
|
成为嵌入式工程师,修好桌面上的<a href="https://www.bilibili.com/video/BV1VA411p7MD">HoloCubic</a>。
|
||||||
|
完成第一个不是课程设计的个人开源项目。
|
||||||
|
遇到能够搭伙过日子的人也算是一大梦想,虽然社恐人根本不知道从何开始的说,
|
||||||
|
<span class="line-through">什么时候天上才能掉美少女?</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="py-2">
|
||||||
|
公开的联系渠道是<a href="mailto:shicangjuner@outlook.com">电子邮件</a>。
|
||||||
|
也可以试试在各大平台搜索上面提到的名字。
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-col p-2">
|
||||||
|
<div class="pb-2">
|
||||||
|
<h3 class="text-2xl">关于本站</h3>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="py-2">
|
||||||
|
本站肇始于2021年下半年,在开始的两年中个人网站和博客是分别的两个网站,个人网站是裸HTML写的,博客是用
|
||||||
|
<a href="https://hexo.io">Hexo</a>渲染的。
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="py-2">
|
||||||
|
2024年,我们决定使用.NET技术完全重构两个网站,合二为一。虽然目前这个版本还是一个半成品,但是我们一定会努力的~(确信。
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="py-2">
|
||||||
|
2025年,我们将使用的样式库从Bootstrap迁移到Tailwind CSS,将现代的前端技术同Blazor结合起来。
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@code {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@foreach (IGrouping<DateTimeOffset, BlogEssay> group in _essays)
|
@foreach (IGrouping<DateTime, BlogEssay> group in _essays)
|
||||||
{
|
{
|
||||||
<div class="p-2">
|
<div class="p-2">
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
@@ -30,7 +30,7 @@
|
|||||||
<div class="px-4 py-4 flex flex-col">
|
<div class="px-4 py-4 flex flex-col">
|
||||||
@foreach (BlogEssay essay in group)
|
@foreach (BlogEssay essay in group)
|
||||||
{
|
{
|
||||||
<a href="@($"/blog/essays/{essay.FileName}")">
|
<a target="_blank" href="@($"/blog/essays/{essay.FileName}")">
|
||||||
<div class="flex flex-row p-2 mx-1 rounded-lg hover:bg-gray-300">
|
<div class="flex flex-row p-2 mx-1 rounded-lg hover:bg-gray-300">
|
||||||
<div class="w-20">
|
<div class="w-20">
|
||||||
@(essay.PublishTime.ToString("MM月dd日"))
|
@(essay.PublishTime.ToString("MM月dd日"))
|
||||||
@@ -51,13 +51,13 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
private readonly List<IGrouping<DateTimeOffset, BlogEssay>> _essays = [];
|
private readonly List<IGrouping<DateTime, BlogEssay>> _essays = [];
|
||||||
|
|
||||||
protected override void OnInitialized()
|
protected override void OnInitialized()
|
||||||
{
|
{
|
||||||
base.OnInitialized();
|
base.OnInitialized();
|
||||||
|
|
||||||
_essays.AddRange(from essay in Contents.Essays
|
_essays.AddRange(from essay in Contents.Essays
|
||||||
group essay by new DateTimeOffset(essay.PublishTime.Year, 1, 1,0, 0, 0, TimeSpan.Zero));
|
group essay by new DateTime(essay.PublishTime.Year, 1, 1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -39,11 +39,6 @@
|
|||||||
{
|
{
|
||||||
_page = Page ?? 1;
|
_page = Page ?? 1;
|
||||||
_pageCount = Contents.Count / EssaysPerPage + 1;
|
_pageCount = Contents.Count / EssaysPerPage + 1;
|
||||||
(_pageCount, int reminder) = int.DivRem(Contents.Count, EssaysPerPage);
|
|
||||||
if (reminder > 0)
|
|
||||||
{
|
|
||||||
_pageCount += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (EssaysPerPage * _page > Contents.Count + EssaysPerPage)
|
if (EssaysPerPage * _page > Contents.Count + EssaysPerPage)
|
||||||
{
|
{
|
||||||
@@ -12,42 +12,47 @@
|
|||||||
|
|
||||||
<div class="flex flex-col py-8">
|
<div class="flex flex-col py-8">
|
||||||
<div>
|
<div>
|
||||||
<div class="flex flex-col items-center">
|
<h1 id="title" class="text-4xl">@(_essay!.Title)</h1>
|
||||||
<div>
|
<div class="col-auto">
|
||||||
<h1 id="title" class="text-4xl">@(_essay!.Title)</h1>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="px-6 pt-4 pb-2">
|
||||||
|
<div class="flex flex-row gap-4">
|
||||||
|
<div class="font-light">
|
||||||
|
@(_essay!.PublishTime.ToString("yyyy-MM-dd"))
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex flex-row gap-4 py-2">
|
@foreach (string tag in _essay!.Tags)
|
||||||
@foreach (string tag in _essay!.Tags)
|
|
||||||
{
|
|
||||||
<div class="text-sky-500">
|
|
||||||
<a href="/blog/tags/?tagName=@(UrlEncoder.Default.Encode(tag))">
|
|
||||||
# @(tag)
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="font-light pb-1">
|
|
||||||
发布于: @(_essay.PublishTime.ToString("yyyy年MM月dd日 HH:mm:ss"))
|
|
||||||
</div>
|
|
||||||
|
|
||||||
@if (_essay.UpdateTime != _essay.PublishTime)
|
|
||||||
{
|
{
|
||||||
<div class="font-light pb-1">
|
<div class="text-sky-500">
|
||||||
更新于: @(_essay.UpdateTime.ToString("yyyy年MM月dd日 HH:mm:ss"))
|
<a href="/blog/tags/?tagName=@(UrlEncoder.Default.Encode(tag))">
|
||||||
|
# @(tag)
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="font-light pb-1">
|
<div class="px-6 pt-2 pb-4">
|
||||||
总字数:@(_essay!.WordCount)字,预计阅读时间 @(_essay!.ReadTime)
|
<div class="font-light">
|
||||||
</div>
|
总字数:@(_essay!.WordCount)字,预计阅读时间 @(_essay!.ReadTime)。
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="grid grid-cols-3">
|
<div class="grid grid-cols-3">
|
||||||
|
<div class="col-span-3 md:col-span-2 flex flex-col gap-3">
|
||||||
|
<div>
|
||||||
|
@((MarkupString)_essay!.HtmlContent)
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<LicenseDisclaimer EssayFilename="@BlogKey"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="col-span-3 md:col-span-1">
|
<div class="col-span-3 md:col-span-1">
|
||||||
<div class="flex flex-col sticky top-20 px-8 pt-20">
|
<div class="flex flex-col sticky top-0 px-8">
|
||||||
<div>
|
<div>
|
||||||
<h3 class="text-2xl">文章目录</h3>
|
<h3 class="text-2xl">文章目录</h3>
|
||||||
</div>
|
</div>
|
||||||
@@ -88,17 +93,8 @@
|
|||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-span-3 md:col-span-2 flex flex-col gap-3">
|
|
||||||
<div>
|
|
||||||
@((MarkupString)_essay!.HtmlContent)
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<LicenseDisclaimer EssayFilename="@BlogKey"/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
59
YaeBlog/Pages/Index.razor
Normal file
59
YaeBlog/Pages/Index.razor
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
@page "/"
|
||||||
|
|
||||||
|
<PageTitle>
|
||||||
|
Ricardo's Index
|
||||||
|
</PageTitle>
|
||||||
|
|
||||||
|
<div class="mx-20">
|
||||||
|
<div class="grid grid-cols-3 py-4">
|
||||||
|
<div class="col-span-3 md:col-span-1 p-5 p-lg-0">
|
||||||
|
<img src="images/avatar.png" alt="Ricardo's Avatar" class="h-auto max-w-full">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-span-3 md:col-span-2">
|
||||||
|
<div class="flex flex-col px-3 gap-y-3">
|
||||||
|
<div class="">
|
||||||
|
<div class="text-3xl font-bold">初冬的朝阳 (Ricardo Ren)</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="">
|
||||||
|
<p class="text-lg">a.k.a jackfiled</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="">
|
||||||
|
<p class="text-lg italic">世界很大,时间很长。</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="">
|
||||||
|
<p class="text-lg">
|
||||||
|
平平无奇的计算机科学与技术学徒,连微小的贡献都没做。
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="py-5">
|
||||||
|
<p class="text-lg">恕我不能亲自为您沏茶(?),还是非常欢迎您能够来到我的主页。</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<p class="text-lg py-1">
|
||||||
|
如果您想四处看看,了解一下屏幕对面的人,可以在我的 <Anchor Address="/blog/" Text="博客"/> 看看。
|
||||||
|
如果您对于明光村幼儿园某附属技校的计算机教学感兴趣,您可以移步到
|
||||||
|
<Anchor Address="https://jackfiled.github.io/wiki/" Text="我的学习笔记"/>,
|
||||||
|
<span class="fs-5 text-decoration-line-through">虽然这笔记我自己也木有看过。</span>
|
||||||
|
如果您想批判一下我的代码,在
|
||||||
|
<Anchor Address="https://github.com/jackfiled/" Text="Github"/> 和
|
||||||
|
<Anchor Address="https://git.rrricardo.top/jackfiled/" Text="Gitea"/>
|
||||||
|
都可以找到。
|
||||||
|
</p>
|
||||||
|
<p class="text-lg py-1">
|
||||||
|
如果您真的很闲,也可以四处搜寻一下,也许存在着一些不为人知的彩蛋。
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@code {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -16,7 +16,8 @@ public sealed class EssayStylesPostRenderProcessor : IPostRenderProcessor
|
|||||||
public async Task<BlogEssay> ProcessAsync(BlogEssay essay)
|
public async Task<BlogEssay> ProcessAsync(BlogEssay essay)
|
||||||
{
|
{
|
||||||
BrowsingContext context = new(Configuration.Default);
|
BrowsingContext context = new(Configuration.Default);
|
||||||
IDocument document = await context.OpenAsync(req => req.Content(essay.HtmlContent));
|
IDocument document = await context.OpenAsync(
|
||||||
|
req => req.Content(essay.HtmlContent));
|
||||||
|
|
||||||
ApplyGlobalCssStyles(document);
|
ApplyGlobalCssStyles(document);
|
||||||
BeatifyTable(document);
|
BeatifyTable(document);
|
||||||
@@ -35,7 +36,6 @@ public sealed class EssayStylesPostRenderProcessor : IPostRenderProcessor
|
|||||||
{ "h5", "text-lg font-bold py-1" },
|
{ "h5", "text-lg font-bold py-1" },
|
||||||
{ "p", "p-2" },
|
{ "p", "p-2" },
|
||||||
{ "img", "w-11/12 block mx-auto my-2 rounded-md shadow-md" },
|
{ "img", "w-11/12 block mx-auto my-2 rounded-md shadow-md" },
|
||||||
{ "a", "text-blue-600" }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
private void ApplyGlobalCssStyles(IDocument document)
|
private void ApplyGlobalCssStyles(IDocument document)
|
||||||
@@ -102,33 +102,17 @@ public sealed class EssayStylesPostRenderProcessor : IPostRenderProcessor
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 美化各种列表元素
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="document"></param>
|
|
||||||
private static void BeatifyList(IDocument document)
|
private static void BeatifyList(IDocument document)
|
||||||
{
|
{
|
||||||
foreach (IElement listElement in from e in document.All
|
foreach (IElement ulElement in from e in document.All
|
||||||
where e.LocalName is "ol" or "ul"
|
where e.LocalName == "ul"
|
||||||
select e)
|
select e)
|
||||||
{
|
{
|
||||||
// 给有序或者无序列表添加不同的样式
|
// 首先给<ul>元素添加样式
|
||||||
listElement.ClassList.Add("ml-10");
|
ulElement.ClassList.Add("list-disc ml-10");
|
||||||
switch (listElement.LocalName)
|
|
||||||
{
|
|
||||||
case "ul":
|
|
||||||
{
|
|
||||||
listElement.ClassList.Add("list-disc");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case "ol":
|
|
||||||
{
|
|
||||||
listElement.ClassList.Add("list-decimal");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (IElement liElement in from e in listElement.Children
|
|
||||||
|
foreach (IElement liElement in from e in ulElement.Children
|
||||||
where e.LocalName == "li"
|
where e.LocalName == "li"
|
||||||
select e)
|
select e)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -16,11 +16,11 @@ public sealed class BlogHotReloadService(
|
|||||||
|
|
||||||
await rendererService.RenderAsync(true);
|
await rendererService.RenderAsync(true);
|
||||||
|
|
||||||
Task[] reloadTasks = [WatchFileAsync(stoppingToken)];
|
Task[] reloadTasks = [FileWatchTask(stoppingToken)];
|
||||||
await Task.WhenAll(reloadTasks);
|
await Task.WhenAll(reloadTasks);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task WatchFileAsync(CancellationToken token)
|
private async Task FileWatchTask(CancellationToken token)
|
||||||
{
|
{
|
||||||
while (!token.IsCancellationRequested)
|
while (!token.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
@@ -33,15 +33,6 @@ public sealed class BlogHotReloadService(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
FileInfo changeFileInfo = new(changeFile);
|
|
||||||
|
|
||||||
if (changeFileInfo.Name.StartsWith('.'))
|
|
||||||
{
|
|
||||||
// Ignore dot-started file and directory.
|
|
||||||
logger.LogDebug("Ignore hidden file: {}.", changeFile);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.LogInformation("{} changed, re-rendering.", changeFile);
|
logger.LogInformation("{} changed, re-rendering.", changeFile);
|
||||||
essayContentService.Clear();
|
essayContentService.Clear();
|
||||||
await rendererService.RenderAsync(true);
|
await rendererService.RenderAsync(true);
|
||||||
|
|||||||
@@ -109,12 +109,6 @@ public partial class EssayScanService : IEssayScanService
|
|||||||
{
|
{
|
||||||
foreach (BlogResult blog in fileContents)
|
foreach (BlogResult blog in fileContents)
|
||||||
{
|
{
|
||||||
if (blog.BlogContent.Length < 4)
|
|
||||||
{
|
|
||||||
// Even not contains a legal header.
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
int endPos = blog.BlogContent.IndexOf("---", 4, StringComparison.Ordinal);
|
int endPos = blog.BlogContent.IndexOf("---", 4, StringComparison.Ordinal);
|
||||||
if (!blog.BlogContent.StartsWith("---") || endPos is -1 or 0)
|
if (!blog.BlogContent.StartsWith("---") || endPos is -1 or 0)
|
||||||
{
|
{
|
||||||
@@ -127,14 +121,14 @@ public partial class EssayScanService : IEssayScanService
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
MarkdownMetadata metadata = _yamlDeserializer.Deserialize<MarkdownMetadata>(metadataString);
|
MarkdownMetadata metadata = _yamlDeserializer.Deserialize<MarkdownMetadata>(metadataString);
|
||||||
_logger.LogDebug("Scan metadata title: '{title}' for {name}.", metadata.Title, blog.BlogFile.Name);
|
_logger.LogDebug("Scan metadata title: '{}' for {}.", metadata.Title, blog.BlogFile.Name);
|
||||||
|
|
||||||
contents.Add(new BlogContent(blog.BlogFile, metadata, blog.BlogContent[(endPos + 3)..], isDraft,
|
contents.Add(new BlogContent(blog.BlogFile, metadata, blog.BlogContent[(endPos + 3)..], isDraft,
|
||||||
blog.Images, blog.NotFoundImages));
|
blog.Images, blog.NotFoundImages));
|
||||||
}
|
}
|
||||||
catch (YamlException e)
|
catch (YamlException e)
|
||||||
{
|
{
|
||||||
_logger.LogWarning("Failed to parser metadata from {name} due to {exception}, skipping", blog.BlogFile.Name, e);
|
_logger.LogWarning("Failed to parser metadata from {} due to {}, skipping", blog.BlogFile.Name, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,62 +0,0 @@
|
|||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -9,7 +9,7 @@ using YaeBlog.Models;
|
|||||||
|
|
||||||
namespace YaeBlog.Services;
|
namespace YaeBlog.Services;
|
||||||
|
|
||||||
public sealed partial class RendererService(
|
public partial class RendererService(
|
||||||
ILogger<RendererService> logger,
|
ILogger<RendererService> logger,
|
||||||
IEssayScanService essayScanService,
|
IEssayScanService essayScanService,
|
||||||
MarkdownPipeline markdownPipeline,
|
MarkdownPipeline markdownPipeline,
|
||||||
@@ -38,15 +38,7 @@ public sealed partial class RendererService(
|
|||||||
List<BlogEssay> essays = [];
|
List<BlogEssay> essays = [];
|
||||||
foreach (BlogContent content in preProcessedContents)
|
foreach (BlogContent content in preProcessedContents)
|
||||||
{
|
{
|
||||||
(uint wordCount, string readTime) = GetWordCount(content);
|
uint wordCount = GetWordCount(content);
|
||||||
DateTimeOffset publishDate = content.Metadata.Date is null
|
|
||||||
? DateTimeOffset.Now
|
|
||||||
: DateTimeOffset.Parse(content.Metadata.Date);
|
|
||||||
// 如果不存在最后的更新时间,就把更新时间设置为发布时间
|
|
||||||
DateTimeOffset updateTime = content.Metadata.UpdateTime is null
|
|
||||||
? publishDate
|
|
||||||
: DateTimeOffset.Parse(content.Metadata.UpdateTime);
|
|
||||||
|
|
||||||
BlogEssay essay = new()
|
BlogEssay essay = new()
|
||||||
{
|
{
|
||||||
Title = content.Metadata.Title ?? content.BlogName,
|
Title = content.Metadata.Title ?? content.BlogName,
|
||||||
@@ -54,9 +46,8 @@ public sealed partial class RendererService(
|
|||||||
IsDraft = content.IsDraft,
|
IsDraft = content.IsDraft,
|
||||||
Description = GetDescription(content),
|
Description = GetDescription(content),
|
||||||
WordCount = wordCount,
|
WordCount = wordCount,
|
||||||
ReadTime = readTime,
|
ReadTime = CalculateReadTime(wordCount),
|
||||||
PublishTime = publishDate,
|
PublishTime = content.Metadata.Date ?? DateTime.Now,
|
||||||
UpdateTime = updateTime,
|
|
||||||
HtmlContent = content.Content
|
HtmlContent = content.Content
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -191,21 +182,28 @@ public sealed partial class RendererService(
|
|||||||
|
|
||||||
string description = builder.ToString();
|
string description = builder.ToString();
|
||||||
|
|
||||||
logger.LogDebug("Description of {name} is {desc}.", content.BlogName,
|
logger.LogDebug("Description of {} is {}.", content.BlogName,
|
||||||
description);
|
description);
|
||||||
return description;
|
return description;
|
||||||
}
|
}
|
||||||
|
|
||||||
private (uint, string) GetWordCount(BlogContent content)
|
private uint GetWordCount(BlogContent content)
|
||||||
{
|
{
|
||||||
uint count = MarkdownWordCounter.CountWord(content);
|
int count = (from c in content.Content
|
||||||
|
where char.IsLetterOrDigit(c)
|
||||||
|
select c).Count();
|
||||||
|
|
||||||
logger.LogDebug("Word count of {blog} is {count}", content.BlogName,
|
logger.LogDebug("Word count of {} is {}", content.BlogName,
|
||||||
count);
|
count);
|
||||||
// 据说语文教学大纲规定,中国高中生阅读现代文的速度是600字每分钟
|
return (uint)count;
|
||||||
uint second = count / 10;
|
}
|
||||||
TimeSpan span = new(0, 0, (int)second);
|
|
||||||
|
|
||||||
return (count, span.ToString("mm'分'ss'秒'"));
|
private static string CalculateReadTime(uint wordCount)
|
||||||
|
{
|
||||||
|
// 据说语文教学大纲规定,中国高中生阅读现代文的速度是600字每分钟
|
||||||
|
int second = (int)wordCount / 10;
|
||||||
|
TimeSpan span = new(0, 0, second);
|
||||||
|
|
||||||
|
return span.ToString("mm'分 'ss'秒'");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,13 +11,30 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net10.0</TargetFramework>
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<Target Name="EnsurePnpmInstalled" BeforeTargets="BeforeBuild">
|
||||||
<ClientAssetsRestoreCommand>pnpm install</ClientAssetsRestoreCommand>
|
<Message Importance="low" Text="Ensure pnpm is installed..."/>
|
||||||
<ClientAssetsBuildCommand>pwsh build.ps1 tailwind</ClientAssetsBuildCommand>
|
<Exec Command="pnpm --version" ContinueOnError="true">
|
||||||
</PropertyGroup>
|
<Output TaskParameter="ExitCode" PropertyName="ErrorCode"/>
|
||||||
|
</Exec>
|
||||||
|
|
||||||
|
<Error Condition="$(ErrorCode) != 0" Text="Pnpm is not installed which is required for build."/>
|
||||||
|
|
||||||
|
<Message Importance="normal" Text="Installing pakages using pnpm..."/>
|
||||||
|
<Exec Command="pnpm install"/>
|
||||||
|
</Target>
|
||||||
|
|
||||||
|
<Target Name="TailwindGenerate" AfterTargets="EnsurePnpmInstalled" BeforeTargets="BeforeBuild" Condition="'$(_IsPublishing)' == 'yes'">
|
||||||
|
<Message Importance="normal" Text="Generate css files using tailwind..."/>
|
||||||
|
<Exec Command="pnpm tailwindcss -i wwwroot/tailwind.css -o $(IntermediateOutputPath)tailwind.g.css"/>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Include="$(IntermediateOutputPath)tailwind.g.css" Visible="false" TargetPath="wwwroot/tailwind.g.css"/>
|
||||||
|
</ItemGroup>
|
||||||
|
</Target>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -6,4 +6,5 @@
|
|||||||
@using static Microsoft.AspNetCore.Components.Web.RenderMode
|
@using static Microsoft.AspNetCore.Components.Web.RenderMode
|
||||||
@using Microsoft.AspNetCore.Components.Web.Virtualization
|
@using Microsoft.AspNetCore.Components.Web.Virtualization
|
||||||
@using Microsoft.JSInterop
|
@using Microsoft.JSInterop
|
||||||
|
@using YaeBlog
|
||||||
@using YaeBlog.Components
|
@using YaeBlog.Components
|
||||||
@@ -21,6 +21,12 @@
|
|||||||
"Link": "https://ichirinko.top",
|
"Link": "https://ichirinko.top",
|
||||||
"AvatarImage": "https://ichirinko-blog-img-1.oss-cn-shenzhen.aliyuncs.com/Pic_res/img/202209122110798.png"
|
"AvatarImage": "https://ichirinko-blog-img-1.oss-cn-shenzhen.aliyuncs.com/Pic_res/img/202209122110798.png"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"Name": "志田千陽",
|
||||||
|
"Description": "日出多值得",
|
||||||
|
"Link": "https://zzachary.top/",
|
||||||
|
"AvatarImage": "https://zzachary.top/img/ztqy_hub928259802d192ff5718c06370f0f2c4_48203_300x0_resize_q75_box.jpg"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"Name": "不会写程序的晨旭",
|
"Name": "不会写程序的晨旭",
|
||||||
"Description": "一个普通大学生",
|
"Description": "一个普通大学生",
|
||||||
@@ -31,7 +37,7 @@
|
|||||||
"Name": "万木长风",
|
"Name": "万木长风",
|
||||||
"Description": "世界渲染中...",
|
"Description": "世界渲染中...",
|
||||||
"Link": "https://ryohai.fun",
|
"Link": "https://ryohai.fun",
|
||||||
"AvatarImage": "https://ryohai.fun/static/favicons/favicon-32x32.png"
|
"AvatarImage": "https://ryohai.fun/icon.jpg"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,124 +0,0 @@
|
|||||||
#!pwsh
|
|
||||||
|
|
||||||
[cmdletbinding()]
|
|
||||||
param(
|
|
||||||
[Parameter(Mandatory = $true, Position = 0, HelpMessage = "Specify the build target")]
|
|
||||||
[ValidateSet("tailwind", "publish", "compress", "build", "dev", "new")]
|
|
||||||
[string]$Target,
|
|
||||||
[string]$Output = "wwwroot",
|
|
||||||
[string]$Essay,
|
|
||||||
[switch]$Compress
|
|
||||||
)
|
|
||||||
|
|
||||||
begin {
|
|
||||||
Write-Host "Building $Target..."
|
|
||||||
|
|
||||||
if ($Target -eq "publish")
|
|
||||||
{
|
|
||||||
if ($Essay -eq "")
|
|
||||||
{
|
|
||||||
Write-Error "No publish target, please add with --essay argument."
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($Target -eq "new")
|
|
||||||
{
|
|
||||||
if ($Essay -eq "")
|
|
||||||
{
|
|
||||||
Write-Error "No new name, please add with --essay argument."
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
process {
|
|
||||||
function Compress-Image
|
|
||||||
{
|
|
||||||
Write-Host "Compress image assets..."
|
|
||||||
dotnet run -- compress --dry-run
|
|
||||||
$confirm = Read-Host "Really compress images? (y/n)"
|
|
||||||
if ($confirm -notmatch "^[yY]$")
|
|
||||||
{
|
|
||||||
Write-Host "Not compress images."
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Host "Do compress image..."
|
|
||||||
dotnet run -- compress
|
|
||||||
|
|
||||||
dotnet run -- scan
|
|
||||||
$confirm = Read-Host "Really delete unused images? (y/n)"
|
|
||||||
if ($confirm -notmatch "^[yY]$")
|
|
||||||
{
|
|
||||||
Write-Host "Not delete images."
|
|
||||||
return
|
|
||||||
}
|
|
||||||
Write-Host "Do delete unused images.."
|
|
||||||
dotnet run -- scan --rm
|
|
||||||
}
|
|
||||||
|
|
||||||
function Build-Image
|
|
||||||
{
|
|
||||||
$commitId = git rev-parse --short=10 HEAD
|
|
||||||
dotnet publish
|
|
||||||
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" {
|
|
||||||
Write-Host "Build tailwind css into $Output."
|
|
||||||
pnpm tailwindcss -i wwwroot/tailwind.css -o $Output/tailwind.g.css
|
|
||||||
break
|
|
||||||
}
|
|
||||||
"publish" {
|
|
||||||
Write-Host "Publish essay $Essay..."
|
|
||||||
dotnet run -- publish $Essay
|
|
||||||
|
|
||||||
if ($Compress)
|
|
||||||
{
|
|
||||||
Compress-Image
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
"compress" {
|
|
||||||
Compress-Image
|
|
||||||
break
|
|
||||||
}
|
|
||||||
"build" {
|
|
||||||
Build-Image
|
|
||||||
break
|
|
||||||
}
|
|
||||||
"dev" {
|
|
||||||
Start-Develop
|
|
||||||
break
|
|
||||||
}
|
|
||||||
"new" {
|
|
||||||
dotnet run -- new $Essay
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
version: '3.8'
|
version: '3.8'
|
||||||
|
|
||||||
services:
|
services:
|
||||||
blog:
|
blog:
|
||||||
image: registry.cn-beijing.aliyuncs.com/jackfiled/blog:latest
|
image: registry.cn-beijing.aliyuncs.com/jackfiled/blog:latest
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
labels:
|
labels:
|
||||||
- "traefik.enable=true"
|
- "traefik.enable=true"
|
||||||
- "traefik.http.routers.blog.rule=Host(`rrricardo.top`) || Host(`www.rrricardo.top`)"
|
- "traefik.http.routers.blog.rule=Host(`rrricardo.top`) || Host(`www.rrricardo.top`)"
|
||||||
- "traefik.http.services.blog.loadbalancer.server.port=8080"
|
- "traefik.http.services.blog.loadbalancer.server.port=8080"
|
||||||
- "traefik.http.routers.blog.tls=true"
|
- "traefik.http.routers.blog.tls=true"
|
||||||
- "traefik.http.routers.blog.tls.certresolver=myresolver"
|
- "traefik.http.routers.blog.tls.certresolver=myresolver"
|
||||||
- "com.centurylinklabs.watchtower.enable=true"
|
- "com.centurylinklabs.watchtower.enable=true"
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
---
|
---
|
||||||
title: High Performance Computing 25 SP NVIDIA
|
title: High Performance Computing 25 SP NVIDIA
|
||||||
date: 2025-08-31T13:50:42.8639950+08:00
|
date: 2025-04-24T19:02:36.1077330+08:00
|
||||||
tags:
|
tags:
|
||||||
- 高性能计算
|
- 高性能计算
|
||||||
- 学习资料
|
- 学习资料
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Fxxk you, NVIDIA!
|
Fxxk you, NVIDIA!
|
||||||
|
|
||||||
<!--more-->
|
<!--more-->
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
---
|
||||||
|
title: High Performance Computing 25 SP Quantum Computing
|
||||||
|
date: 2025-06-12T19:26:24.6668760+08:00
|
||||||
|
tags:
|
||||||
|
- 高性能计算
|
||||||
|
- 学习资料
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
<!--more-->
|
||||||
@@ -1,13 +1,11 @@
|
|||||||
---
|
---
|
||||||
title: High Performance Computing 25 SP Non Stored Program Computing
|
title: High Performance Computing 2025 SP Non Stored Program Computing
|
||||||
date: 2025-08-31T13:51:17.5260660+08:00
|
date: 2025-05-29T18:29:28.6155560+08:00
|
||||||
tags:
|
tags:
|
||||||
- 高性能计算
|
- 高性能计算
|
||||||
- 学习资料
|
- 学习资料
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
No Von Neumann Machines.
|
No Von Neumann Machines.
|
||||||
|
|
||||||
<!--more-->
|
<!--more-->
|
||||||
@@ -62,7 +60,7 @@ There are two types of semi-custom ASICs:
|
|||||||
|
|
||||||
The Standard cell based ASICs is also called as **Cell-based ASIC(CBIC)**.
|
The Standard cell based ASICs is also called as **Cell-based ASIC(CBIC)**.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
> The *gate* is used a unit to measure the ability of semiconductor to store logical elements.
|
> The *gate* is used a unit to measure the ability of semiconductor to store logical elements.
|
||||||
|
|
||||||
@@ -86,7 +84,7 @@ Depending on the structure, the standard PLD can be divided into:
|
|||||||
- Programmable Logic Array(PLA): A programmable array of AND gates feeding a programmable of OR gates.
|
- Programmable Logic Array(PLA): A programmable array of AND gates feeding a programmable of OR gates.
|
||||||
- Complex Programmable Logic Device(CPLD) and Field Programmable Gate Array(FPGA): complex enough to be called as *architecture*.
|
- Complex Programmable Logic Device(CPLD) and Field Programmable Gate Array(FPGA): complex enough to be called as *architecture*.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -98,7 +96,7 @@ Depending on the structure, the standard PLD can be divided into:
|
|||||||
|
|
||||||
### FPGA Architecture
|
### FPGA Architecture
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
#### Configurable Logic Block(CLB) Architecture
|
#### Configurable Logic Block(CLB) Architecture
|
||||||
|
|
||||||
@@ -118,7 +116,7 @@ LUT is a ram with data width of 1 bit and the content is programmed at power up.
|
|||||||
|
|
||||||
The below figure shows LUT working:
|
The below figure shows LUT working:
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
The configuration memory holds the output of truth table entries, so that when the FPGA is restarting it will run with the same *program*.
|
The configuration memory holds the output of truth table entries, so that when the FPGA is restarting it will run with the same *program*.
|
||||||
|
|
||||||
@@ -128,7 +126,7 @@ And as the truth table entries are just bits, the program of FPGA is called as *
|
|||||||
|
|
||||||
Let the input signal as address, the LUT will be configured as a RAM. Normally, LUT mode performs read operations, the address decoders can generate clock signal to latches for writing operation.
|
Let the input signal as address, the LUT will be configured as a RAM. Normally, LUT mode performs read operations, the address decoders can generate clock signal to latches for writing operation.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
#### Routing Architecture
|
#### Routing Architecture
|
||||||
|
|
||||||
@@ -136,7 +134,7 @@ The logic blocks are connected to each though programmable routing network. And
|
|||||||
|
|
||||||
Horizontal and vertical mesh or wire segments interconnection by programmable switches called programmable interconnect points(PIPs).
|
Horizontal and vertical mesh or wire segments interconnection by programmable switches called programmable interconnect points(PIPs).
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
These PIPs are implemented using a transmission gate controlled by a memory bits from the configuration memory.
|
These PIPs are implemented using a transmission gate controlled by a memory bits from the configuration memory.
|
||||||
|
|
||||||
@@ -148,7 +146,7 @@ Several types of PIPs are used in the FPGA:
|
|||||||
- Non-decoded MUX: n wire segments each with a configuration bit.
|
- Non-decoded MUX: n wire segments each with a configuration bit.
|
||||||
- Compound cross-point: 6 breakpoint PIPs and can isolate two isolated signal nets.
|
- Compound cross-point: 6 breakpoint PIPs and can isolate two isolated signal nets.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
#### Input/Output Architecture
|
#### Input/Output Architecture
|
||||||
|
|
||||||
@@ -160,7 +158,7 @@ The programmable Input/Output cells consists of three parts:
|
|||||||
- Routing resources.
|
- Routing resources.
|
||||||
- Programmable I/O voltage and current levels.
|
- Programmable I/O voltage and current levels.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
#### Fine-grained and Coarse-grained Architecture
|
#### Fine-grained and Coarse-grained Architecture
|
||||||
|
|
||||||
@@ -188,9 +186,9 @@ Three types of interconnected devices have been commonly used to connect there w
|
|||||||
|
|
||||||
### FPGA Design Flow
|
### FPGA Design Flow
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
The FPGA configuration techniques contains:
|
The FPGA configuration techniques contains:
|
||||||
|
|
||||||
@@ -224,7 +222,7 @@ The OpenCL is not an traditional hardare description language. And OpenCL needs
|
|||||||
|
|
||||||
The follow figure shows how the OpenCL-FPGA compiler turns an vector adding function into the circuit.
|
The follow figure shows how the OpenCL-FPGA compiler turns an vector adding function into the circuit.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
The compiler generates three stages for this function:
|
The compiler generates three stages for this function:
|
||||||
|
|
||||||
BIN
YaeBlog/source/drafts/hpc-2025-non-stored-program-computing/image-20250815093113115.png
(Stored with Git LFS)
Normal file
BIN
YaeBlog/source/drafts/hpc-2025-non-stored-program-computing/image-20250815093113115.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
YaeBlog/source/drafts/hpc-2025-non-stored-program-computing/image-20250817183832472.png
(Stored with Git LFS)
Normal file
BIN
YaeBlog/source/drafts/hpc-2025-non-stored-program-computing/image-20250817183832472.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
YaeBlog/source/drafts/hpc-2025-non-stored-program-computing/image-20250817184419856.png
(Stored with Git LFS)
Normal file
BIN
YaeBlog/source/drafts/hpc-2025-non-stored-program-computing/image-20250817184419856.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
YaeBlog/source/drafts/hpc-2025-non-stored-program-computing/image-20250817185111521.png
(Stored with Git LFS)
Normal file
BIN
YaeBlog/source/drafts/hpc-2025-non-stored-program-computing/image-20250817185111521.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
YaeBlog/source/drafts/hpc-2025-non-stored-program-computing/image-20250817185859510.png
(Stored with Git LFS)
Normal file
BIN
YaeBlog/source/drafts/hpc-2025-non-stored-program-computing/image-20250817185859510.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
YaeBlog/source/drafts/hpc-2025-non-stored-program-computing/image-20250817192006784.png
(Stored with Git LFS)
Normal file
BIN
YaeBlog/source/drafts/hpc-2025-non-stored-program-computing/image-20250817192006784.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
YaeBlog/source/drafts/hpc-2025-non-stored-program-computing/image-20250817194355228.png
(Stored with Git LFS)
Normal file
BIN
YaeBlog/source/drafts/hpc-2025-non-stored-program-computing/image-20250817194355228.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
YaeBlog/source/drafts/hpc-2025-non-stored-program-computing/image-20250817195139631.png
(Stored with Git LFS)
Normal file
BIN
YaeBlog/source/drafts/hpc-2025-non-stored-program-computing/image-20250817195139631.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
YaeBlog/source/drafts/hpc-2025-non-stored-program-computing/image-20250817195714935.png
(Stored with Git LFS)
Normal file
BIN
YaeBlog/source/drafts/hpc-2025-non-stored-program-computing/image-20250817195714935.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
YaeBlog/source/drafts/hpc-2025-non-stored-program-computing/image-20250817200350750.png
(Stored with Git LFS)
Normal file
BIN
YaeBlog/source/drafts/hpc-2025-non-stored-program-computing/image-20250817200350750.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
YaeBlog/source/drafts/hpc-2025-non-stored-program-computing/image-20250829210329225.png
(Stored with Git LFS)
Normal file
BIN
YaeBlog/source/drafts/hpc-2025-non-stored-program-computing/image-20250829210329225.png
(Stored with Git LFS)
Normal file
Binary file not shown.
@@ -1,12 +1,11 @@
|
|||||||
---
|
---
|
||||||
title: High Performance Computing 25 SP OpenCL Programming
|
title: High Performance Computing 2025 SP OpenCL Programming
|
||||||
date: 2025-08-31T13:51:02.0181970+08:00
|
date: 2025-05-29T18:29:14.8444660+08:00
|
||||||
tags:
|
tags:
|
||||||
- 高性能计算
|
- 高性能计算
|
||||||
- 学习资料
|
- 学习资料
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
||||||
Open Computing Language.
|
Open Computing Language.
|
||||||
|
|
||||||
<!--more-->
|
<!--more-->
|
||||||
@@ -1,12 +1,11 @@
|
|||||||
---
|
---
|
||||||
title: High Performance Computing 25 SP Potpourri
|
title: High Performance Computing 25 SP Potpourri
|
||||||
date: 2025-08-31T13:51:29.8809980+08:00
|
date: 2025-06-12T18:45:49.2698190+08:00
|
||||||
tags:
|
tags:
|
||||||
- 高性能计算
|
- 高性能计算
|
||||||
- 学习资料
|
- 学习资料
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
||||||
Potpourri has a good taste.
|
Potpourri has a good taste.
|
||||||
|
|
||||||
<!--more-->
|
<!--more-->
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user