Updated views, added static to gitignore properly
This commit is contained in:
parent
8c2dccde3e
commit
a3d818a80a
|
|
@ -2,8 +2,7 @@
|
|||
*.db
|
||||
|
||||
# STATIC
|
||||
wwwroot/static/
|
||||
|
||||
src/FastBlog.Web/wwwroot/static/
|
||||
# BLOGS
|
||||
md/
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ public interface IBlogMetaRepository
|
|||
{
|
||||
Task<BlogMeta?> Get(string? slug);
|
||||
Task<BlogMeta?> GetForEdit(int id);
|
||||
Task<bool> Delete(int id);
|
||||
Task<Result<BlogMeta, BusinessError>> Add(BlogMeta meta);
|
||||
Task<Result<BlogMeta, BusinessError>> Update(BlogMeta meta);
|
||||
}
|
||||
|
|
@ -58,7 +58,7 @@ public static class DependencyInjection
|
|||
if (mainPage is not null)
|
||||
return;
|
||||
|
||||
await blogService.UpdateBlog(new Blog
|
||||
await blogService.Update(new Blog
|
||||
{
|
||||
Text = BlogDefaultBody,
|
||||
Metadata = new BlogMeta
|
||||
|
|
|
|||
|
|
@ -44,6 +44,19 @@ public sealed class BlogMetaRepository(SqliteConnectionFactory connectionFactory
|
|||
return await connection.QueryFirstOrDefaultAsync<BlogMeta>(sql, new { id });
|
||||
}
|
||||
|
||||
public async Task<bool> Delete(int id)
|
||||
{
|
||||
const string sql = """
|
||||
update Blogs
|
||||
set Deleted = 1
|
||||
where id = @id
|
||||
""";
|
||||
|
||||
using var connection = connectionFactory.Create();
|
||||
|
||||
return await connection.ExecuteAsync(sql, new { id }) > 0;
|
||||
}
|
||||
|
||||
public async Task<Result<BlogMeta, BusinessError>> Add(BlogMeta meta)
|
||||
{
|
||||
using var connection = connectionFactory.Create();
|
||||
|
|
|
|||
|
|
@ -47,12 +47,27 @@ public sealed class BlogService(IBlogMetaRepository metaRepository, IBlogFileRep
|
|||
}
|
||||
|
||||
|
||||
public Task<Result<Blog, BusinessError>> UpdateBlog(Blog blog)
|
||||
public Task<Result<Blog, BusinessError>> Update(Blog blog)
|
||||
{
|
||||
return blog.Metadata.Id is null ? CreateBlog(blog) : UpdateBlogInternal(blog);
|
||||
return blog.Metadata.Id is null ? Create(blog) : UpdateInternal(blog);
|
||||
}
|
||||
|
||||
private async Task<Result<Blog, BusinessError>> CreateBlog(Blog newBlog)
|
||||
public async Task<bool> Delete(int id)
|
||||
{
|
||||
var meta = await metaRepository.GetForEdit(id);
|
||||
if (meta is null)
|
||||
return false;
|
||||
|
||||
var toDelete = meta.SourceLocation;
|
||||
|
||||
var result = await metaRepository.Delete(id);
|
||||
if (!result)
|
||||
return false;
|
||||
|
||||
return await blogFileRepository.Delete(toDelete);
|
||||
}
|
||||
|
||||
private async Task<Result<Blog, BusinessError>> Create(Blog newBlog)
|
||||
{
|
||||
var metaResult = await metaRepository.Add(newBlog.Metadata);
|
||||
if (metaResult.IsError)
|
||||
|
|
@ -71,7 +86,7 @@ public sealed class BlogService(IBlogMetaRepository metaRepository, IBlogFileRep
|
|||
}
|
||||
|
||||
|
||||
private async Task<Result<Blog, BusinessError>> UpdateBlogInternal(Blog blog)
|
||||
private async Task<Result<Blog, BusinessError>> UpdateInternal(Blog blog)
|
||||
{
|
||||
var oldMeta = await metaRepository.GetForEdit(blog.Metadata.Id!.Value);
|
||||
if (oldMeta is null)
|
||||
|
|
|
|||
|
|
@ -44,12 +44,12 @@ public class BlogsController(BlogService service) : Controller
|
|||
{
|
||||
if (!id.HasValue)
|
||||
{
|
||||
var date = DateTime.Now;
|
||||
var date = DateTime.UtcNow;
|
||||
return View(
|
||||
new EditBlog
|
||||
{
|
||||
Text = "# My new blog",
|
||||
Title = "Blog from " + DateTime.Now.ToString("g"),
|
||||
Title = "Blog from " + DateTime.UtcNow.ToString("g"),
|
||||
SourceLocation = $"{date:yyyy-MM-dd-HH-mm}_blog.md",
|
||||
CreatedAt = date,
|
||||
ModifiedAt = date,
|
||||
|
|
@ -87,7 +87,7 @@ public class BlogsController(BlogService service) : Controller
|
|||
[Route("edit")]
|
||||
public async Task<IActionResult> Edit([FromForm] EditBlog editBlog)
|
||||
{
|
||||
var result = await service.UpdateBlog(new()
|
||||
var result = await service.Update(new()
|
||||
{
|
||||
Text = editBlog.Text,
|
||||
Metadata = new()
|
||||
|
|
@ -141,4 +141,17 @@ public class BlogsController(BlogService service) : Controller
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
[HttpDelete]
|
||||
[Route("{id:int}")]
|
||||
public async Task<IActionResult> Delete(int id)
|
||||
{
|
||||
var result = await service.Delete(id);
|
||||
|
||||
if (!result)
|
||||
return NotFound();
|
||||
|
||||
HttpContext.Response.Headers.Append("Hx-Redirect", "/");
|
||||
return Ok();
|
||||
}
|
||||
}
|
||||
|
|
@ -50,7 +50,7 @@ public class FilesController(FileService fileService) : Controller
|
|||
var meta = new FileMeta
|
||||
{
|
||||
SourceLocation = Path.Combine(sourcePath ?? "", file.FileName),
|
||||
CreatedAt = DateTime.Now,
|
||||
CreatedAt = DateTime.UtcNow,
|
||||
MimeType = file.ContentType
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ else
|
|||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button class="preview-btn secondary" hx-post="/blog/preview" hx-target="#preview" hx-swap="OuterHTML">Preview</button>
|
||||
<button class="preview-btn secondary" hx-post="/blogs/preview" hx-target="#preview" hx-swap="OuterHTML">Preview</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,12 @@
|
|||
|
||||
@{
|
||||
ViewBag.Title = Model.Metadata.Title;
|
||||
var pipelineBuilder = new MarkdownPipelineBuilder().UseAdvancedExtensions().UseHighlightJs();
|
||||
var pipelineBuilder = new MarkdownPipelineBuilder()
|
||||
.UseSmartyPants()
|
||||
.UseEmojiAndSmiley()
|
||||
.UseAlertBlocks()
|
||||
.UseAdvancedExtensions()
|
||||
.UseHighlightJs();
|
||||
var sanitizer = new HtmlSanitizer();
|
||||
sanitizer.AllowedAttributes.Add("class");
|
||||
var pipeline = pipelineBuilder.Build();
|
||||
|
|
@ -37,4 +42,31 @@
|
|||
}
|
||||
|
||||
@Html.Raw(sanitizer.Sanitize(Markdown.ToHtml(Model.Text, pipeline)))
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<br>
|
||||
|
||||
<div class="container">
|
||||
<hr/>
|
||||
<article>
|
||||
<header>
|
||||
<h3>Editor's controls</h3>
|
||||
</header>
|
||||
<body>
|
||||
<div class="grid">
|
||||
<div>
|
||||
<a href="/edit/@Model.Metadata.Id">
|
||||
<button class="btn-fw">
|
||||
Edit
|
||||
</button>
|
||||
</a>
|
||||
</div>
|
||||
<div>
|
||||
<button class="btn-fw secondary" hx-delete="/blogs/@Model.Metadata.Id">
|
||||
Delete
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</article>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,4 @@
|
|||
@using Ganss.Xss
|
||||
@using Markdig;
|
||||
@using Pek.Markdig.HighlightJs
|
||||
@model FastBlog.Core.Models.Blogs.Blog
|
||||
@model FastBlog.Core.Models.Blogs.Blog
|
||||
|
||||
@await Html.PartialAsync("Index", Model);
|
||||
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ return;
|
|||
<ul>
|
||||
<li><a href="~/"><h1>@options.Value.Title</h1></a></li>
|
||||
<li><a href="~/blog/list">Blog</a></li>
|
||||
<li><a href="~/edit">New</a></li>
|
||||
</ul>
|
||||
<ul>
|
||||
@foreach (var link in options.Value.Links)
|
||||
|
|
|
|||
|
|
@ -26,6 +26,9 @@
|
|||
--pico-background-color: #0f1a27;
|
||||
--pico-card-background-color: #132232;
|
||||
--pico-card-sectioning-background-color: #17273a;
|
||||
|
||||
--pico-form-element-background-color: #ffffff08;
|
||||
--pico-form-element-active-background-color: #ffffff18;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
|
|
|
|||
Binary file not shown.
|
Before Width: | Height: | Size: 19 KiB |
Loading…
Reference in New Issue