Added blog list for edit
This commit is contained in:
parent
8ffa4a39fe
commit
fbd7b1c7d3
|
|
@ -5,9 +5,11 @@ namespace FastBlog.Core.Abstractions.Repositories.Blogs;
|
||||||
|
|
||||||
public interface IBlogMetaRepository
|
public interface IBlogMetaRepository
|
||||||
{
|
{
|
||||||
|
Task<BlogMeta?> GetPublished(string? slug);
|
||||||
Task<BlogMeta?> Get(string? slug);
|
Task<BlogMeta?> Get(string? slug);
|
||||||
Task<BlogMeta?> GetForEdit(int id);
|
Task<BlogMeta?> GetForEdit(int id);
|
||||||
Task<bool> Delete(int id);
|
Task<bool> Delete(int id);
|
||||||
Task<Result<BlogMeta, BusinessError>> Add(BlogMeta meta);
|
Task<Result<BlogMeta, BusinessError>> Add(BlogMeta meta);
|
||||||
Task<Result<BlogMeta, BusinessError>> Update(BlogMeta meta);
|
Task<Result<BlogMeta, BusinessError>> Update(BlogMeta meta);
|
||||||
|
Task<PagedResponse<BlogMeta>> List(BlogFilter filter, PagedRequest request);
|
||||||
}
|
}
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Dapper" Version="2.1.35" />
|
<PackageReference Include="Dapper" Version="2.1.35" />
|
||||||
|
<PackageReference Include="Dapper.SqlBuilder" Version="2.0.78" />
|
||||||
<PackageReference Include="FluentMigrator" Version="5.2.0" />
|
<PackageReference Include="FluentMigrator" Version="5.2.0" />
|
||||||
<PackageReference Include="FluentMigrator.Runner.SQLite" Version="5.2.0" />
|
<PackageReference Include="FluentMigrator.Runner.SQLite" Version="5.2.0" />
|
||||||
<PackageReference Include="Microsoft.Data.Sqlite" Version="8.0.8" />
|
<PackageReference Include="Microsoft.Data.Sqlite" Version="8.0.8" />
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
namespace FastBlog.Core.Models.Blogs;
|
||||||
|
|
||||||
|
public sealed record BlogFilter(DateTime? From, DateTime? To, string? Search);
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
using Dapper;
|
using System.Text;
|
||||||
|
using Dapper;
|
||||||
using FastBlog.Core.Abstractions.Repositories.Blogs;
|
using FastBlog.Core.Abstractions.Repositories.Blogs;
|
||||||
using FastBlog.Core.Db;
|
using FastBlog.Core.Db;
|
||||||
using FastBlog.Core.Models;
|
using FastBlog.Core.Models;
|
||||||
|
|
@ -9,7 +10,7 @@ namespace FastBlog.Core.Repositories;
|
||||||
|
|
||||||
public sealed class BlogMetaRepository(SqliteConnectionFactory connectionFactory) : IBlogMetaRepository
|
public sealed class BlogMetaRepository(SqliteConnectionFactory connectionFactory) : IBlogMetaRepository
|
||||||
{
|
{
|
||||||
public async Task<BlogMeta?> Get(string? slug)
|
public async Task<BlogMeta?> GetPublished(string? slug)
|
||||||
{
|
{
|
||||||
using var connection = connectionFactory.Create();
|
using var connection = connectionFactory.Create();
|
||||||
|
|
||||||
|
|
@ -30,6 +31,27 @@ public sealed class BlogMetaRepository(SqliteConnectionFactory connectionFactory
|
||||||
return await connection.QueryFirstOrDefaultAsync<BlogMeta>(sql, new { slug });
|
return await connection.QueryFirstOrDefaultAsync<BlogMeta>(sql, new { slug });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<BlogMeta?> Get(string? slug)
|
||||||
|
{
|
||||||
|
using var connection = connectionFactory.Create();
|
||||||
|
|
||||||
|
const string sqlNull = """
|
||||||
|
select * from Blogs
|
||||||
|
where slug is null
|
||||||
|
""";
|
||||||
|
|
||||||
|
const string sql = """
|
||||||
|
select * from Blogs
|
||||||
|
where (slug = @slug or id = cast(@slug as integer))
|
||||||
|
""";
|
||||||
|
|
||||||
|
if (slug is null)
|
||||||
|
return await connection.QueryFirstOrDefaultAsync<BlogMeta>(sqlNull);
|
||||||
|
|
||||||
|
return await connection.QueryFirstOrDefaultAsync<BlogMeta>(sql, new { slug });
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public async Task<BlogMeta?> GetForEdit(int id)
|
public async Task<BlogMeta?> GetForEdit(int id)
|
||||||
{
|
{
|
||||||
using var connection = connectionFactory.Create();
|
using var connection = connectionFactory.Create();
|
||||||
|
|
@ -98,4 +120,46 @@ public sealed class BlogMetaRepository(SqliteConnectionFactory connectionFactory
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<PagedResponse<BlogMeta>> List(BlogFilter filter, PagedRequest request)
|
||||||
|
{
|
||||||
|
using var connection = connectionFactory.Create();
|
||||||
|
|
||||||
|
var parameters = new DynamicParameters();
|
||||||
|
|
||||||
|
parameters.Add("@Amount", request.Amount);
|
||||||
|
parameters.Add("@Offset", request.Offset);
|
||||||
|
|
||||||
|
var sql = new StringBuilder("""
|
||||||
|
select COUNT(*) from Files;
|
||||||
|
select * from Blogs ""
|
||||||
|
""");
|
||||||
|
|
||||||
|
if (filter.To.HasValue)
|
||||||
|
{
|
||||||
|
sql.AppendLine("where CreatedAt >= @To");
|
||||||
|
parameters.Add("@To", filter.To.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filter.From.HasValue)
|
||||||
|
{
|
||||||
|
sql.AppendLine("where CreatedAt <= @From");
|
||||||
|
parameters.Add("@From", filter.From.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filter.Search is not null)
|
||||||
|
{
|
||||||
|
sql.AppendLine("where Title like @Search");
|
||||||
|
parameters.Add("@Search", $"%{filter.Search}%");
|
||||||
|
}
|
||||||
|
|
||||||
|
sql.AppendLine("order by CreatedAt desc");
|
||||||
|
sql.AppendLine("limit @Amount offset @Offset;");
|
||||||
|
|
||||||
|
await using var multi = await connection.QueryMultipleAsync(sql.ToString(), parameters);
|
||||||
|
var total = await multi.ReadFirstAsync<long>();
|
||||||
|
var result = (await multi.ReadAsync<BlogMeta>()).ToArray();
|
||||||
|
|
||||||
|
return PagedResponse<BlogMeta>.Create(total, request.Amount, request.Offset, result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -6,6 +6,26 @@ namespace FastBlog.Core.Services;
|
||||||
|
|
||||||
public sealed class BlogService(IBlogMetaRepository metaRepository, IBlogFileRepository blogFileRepository)
|
public sealed class BlogService(IBlogMetaRepository metaRepository, IBlogFileRepository blogFileRepository)
|
||||||
{
|
{
|
||||||
|
public async Task<Blog?> GetPublished(string? slug)
|
||||||
|
{
|
||||||
|
slug = slug?.ToLower();
|
||||||
|
var metaResult = await metaRepository.GetPublished(slug);
|
||||||
|
if (metaResult is null)
|
||||||
|
return null;
|
||||||
|
var sourceResult = await blogFileRepository.Read(metaResult.SourceLocation);
|
||||||
|
|
||||||
|
if (sourceResult is null)
|
||||||
|
{
|
||||||
|
throw new FileNotFoundException("File with metadata cannot be found");
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Blog
|
||||||
|
{
|
||||||
|
Metadata = metaResult,
|
||||||
|
Text = sourceResult
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<Blog?> Get(string? slug)
|
public async Task<Blog?> Get(string? slug)
|
||||||
{
|
{
|
||||||
slug = slug?.ToLower();
|
slug = slug?.ToLower();
|
||||||
|
|
@ -26,6 +46,8 @@ public sealed class BlogService(IBlogMetaRepository metaRepository, IBlogFileRep
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Task<PagedResponse<BlogMeta>> ListMetas(BlogFilter filter, PagedRequest request) => metaRepository.List(filter, request);
|
||||||
|
|
||||||
public async Task<Blog?> GetForEdit(int id)
|
public async Task<Blog?> GetForEdit(int id)
|
||||||
{
|
{
|
||||||
var metaResult = await metaRepository.GetForEdit(id);
|
var metaResult = await metaRepository.GetForEdit(id);
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
using System.Diagnostics;
|
using FastBlog.Core.Models;
|
||||||
using FastBlog.Core.Abstractions.Repositories.Blogs;
|
|
||||||
using FastBlog.Core.Models.Blogs;
|
using FastBlog.Core.Models.Blogs;
|
||||||
using FastBlog.Core.Services;
|
using FastBlog.Core.Services;
|
||||||
using FastBlog.Web.Models;
|
using FastBlog.Web.Models;
|
||||||
|
|
@ -18,7 +17,7 @@ public class BlogsController(BlogService service) : Controller
|
||||||
if (string.IsNullOrWhiteSpace(slug))
|
if (string.IsNullOrWhiteSpace(slug))
|
||||||
slug = null;
|
slug = null;
|
||||||
|
|
||||||
var blog = await service.Get(slug);
|
var blog = await service.GetPublished(slug);
|
||||||
|
|
||||||
if (blog is null)
|
if (blog is null)
|
||||||
return NotFound();
|
return NotFound();
|
||||||
|
|
@ -30,7 +29,7 @@ public class BlogsController(BlogService service) : Controller
|
||||||
[Route("")]
|
[Route("")]
|
||||||
public async Task<IActionResult> Index()
|
public async Task<IActionResult> Index()
|
||||||
{
|
{
|
||||||
var blog = await service.Get(null);
|
var blog = await service.GetPublished(null);
|
||||||
|
|
||||||
if (blog is null)
|
if (blog is null)
|
||||||
return NotFound();
|
return NotFound();
|
||||||
|
|
@ -38,6 +37,40 @@ public class BlogsController(BlogService service) : Controller
|
||||||
return View(blog);
|
return View(blog);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
[Route("unpublished/{*slug}")]
|
||||||
|
public async Task<IActionResult> Unpublished(string? slug)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(slug))
|
||||||
|
slug = null;
|
||||||
|
|
||||||
|
var blog = await service.Get(slug);
|
||||||
|
|
||||||
|
if (blog is null)
|
||||||
|
return NotFound();
|
||||||
|
|
||||||
|
return View(blog);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("list/edit")]
|
||||||
|
public async Task<IActionResult> List(
|
||||||
|
[FromQuery(Name = "amount")] int amount = 25,
|
||||||
|
[FromQuery(Name = "offset")] int offset = 0,
|
||||||
|
[FromQuery(Name = "query")] string? query = null,
|
||||||
|
[FromQuery(Name = "from")] DateTime? from = null,
|
||||||
|
[FromQuery(Name = "to")] DateTime? to = null)
|
||||||
|
{
|
||||||
|
|
||||||
|
if(amount is < 1 or > 100)
|
||||||
|
return BadRequest("Amount must be between 1 and 100");
|
||||||
|
|
||||||
|
if(offset < 0)
|
||||||
|
return BadRequest("Offset must be greater than 0");
|
||||||
|
|
||||||
|
return View(await service.ListMetas(new BlogFilter(from,to, query), new PagedRequest(amount, offset)));
|
||||||
|
}
|
||||||
|
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
[Route("edit/{id:int?}")]
|
[Route("edit/{id:int?}")]
|
||||||
public async ValueTask<IActionResult> Edit(int? id)
|
public async ValueTask<IActionResult> Edit(int? id)
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
namespace FastBlog.Web.Models;
|
using System;
|
||||||
|
|
||||||
|
namespace FastBlog.Web.Models;
|
||||||
|
|
||||||
public sealed class EditBlog
|
public sealed class EditBlog
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@ using FastBlog.Web;
|
||||||
|
|
||||||
var builder = WebApplication.CreateBuilder(args);
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
|
|
||||||
// Add services to the container.
|
|
||||||
if (Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") == Environments.Development)
|
if (Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") == Environments.Development)
|
||||||
builder.Services.AddControllersWithViews().AddRazorRuntimeCompilation();
|
builder.Services.AddControllersWithViews().AddRazorRuntimeCompilation();
|
||||||
else
|
else
|
||||||
|
|
@ -14,11 +13,9 @@ builder.Services.Configure<DisplayOptions>(builder.Configuration.GetSection("Dis
|
||||||
|
|
||||||
var app = builder.Build();
|
var app = builder.Build();
|
||||||
|
|
||||||
// Configure the HTTP request pipeline.
|
|
||||||
if (!app.Environment.IsDevelopment())
|
if (!app.Environment.IsDevelopment())
|
||||||
{
|
{
|
||||||
app.UseExceptionHandler("/Home/Error");
|
app.UseExceptionHandler("/Home/Error");
|
||||||
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
app.UseHttpsRedirection();
|
app.UseHttpsRedirection();
|
||||||
|
|
|
||||||
|
|
@ -4,31 +4,11 @@
|
||||||
ViewBag.Title = Model.Metadata.Title;
|
ViewBag.Title = Model.Metadata.Title;
|
||||||
}
|
}
|
||||||
|
|
||||||
@await Html.PartialAsync("Blogs/BlogContent", Model)
|
@await Html.PartialAsync("Blogs/Content", Model)
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<hr/>
|
<hr/>
|
||||||
<article>
|
@await Html.PartialAsync("Blogs/ManageCard", Model.Metadata)
|
||||||
<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>
|
</div>
|
||||||
|
|
@ -0,0 +1,123 @@
|
||||||
|
@using FastBlog.Web.Helpers
|
||||||
|
@model FastBlog.Core.Models.PagedResponse<FastBlog.Core.Models.Blogs.BlogMeta>
|
||||||
|
|
||||||
|
|
||||||
|
@{
|
||||||
|
ViewBag.Title = "Blogs";
|
||||||
|
}
|
||||||
|
|
||||||
|
<div class="container" id="file-list">
|
||||||
|
|
||||||
|
|
||||||
|
<br/>
|
||||||
|
<article>
|
||||||
|
<header>
|
||||||
|
<a href="/edit">
|
||||||
|
<button class="btn-fw secondary">
|
||||||
|
New
|
||||||
|
</button>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<hr/>
|
||||||
|
|
||||||
|
<h3>List of Blogs</h3>
|
||||||
|
</header>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
@if (Model.Data.Length is 0)
|
||||||
|
{
|
||||||
|
<h4>No blogs have been found</h4>
|
||||||
|
}
|
||||||
|
|
||||||
|
<div class="grid">
|
||||||
|
<div style="display: flex; font-size: 16px">
|
||||||
|
<p>Name</p>
|
||||||
|
</div>
|
||||||
|
<div style="display: flex; font-size: 16px">
|
||||||
|
<p>Published</p>
|
||||||
|
</div>
|
||||||
|
<div style="display: flex; font-size: 16px">
|
||||||
|
<p>Visible</p>
|
||||||
|
</div>
|
||||||
|
<div style="display: flex; font-size: 16px">
|
||||||
|
<p>Actions</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@foreach (var blog in Model.Data)
|
||||||
|
{
|
||||||
|
<div class="grid">
|
||||||
|
<div style="display: flex; font-size: 16px">
|
||||||
|
<p class="no-margin" style="margin-right: 10px; font-weight: bold">
|
||||||
|
@if (blog.CreatedAt < DateTime.UtcNow)
|
||||||
|
{
|
||||||
|
<a target="_blank" href="/@blog.Slug">@blog.Title</a>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<a class="pico-color-purple-600" target="_blank" href="/unpublished/@blog.Slug">@blog.Title</a>
|
||||||
|
}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p class="no-margin">
|
||||||
|
@if (blog.CreatedAt < DateTime.UtcNow)
|
||||||
|
{
|
||||||
|
@blog.CreatedAt.ToString("yy-MM-dd HH:mm:ss")
|
||||||
|
;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<span class="pico-color-purple-400">@blog.CreatedAt.ToString("yy-MM-dd HH:mm:ss")</span>
|
||||||
|
;
|
||||||
|
}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p class="no-margin">
|
||||||
|
<strong>
|
||||||
|
@if (blog.Visible)
|
||||||
|
{
|
||||||
|
<spans>Yes</spans>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<span class="pico-color-yellow">No</span>
|
||||||
|
}
|
||||||
|
</strong>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p class="no-margin">
|
||||||
|
<a class="pico-color-red" hx-delete="/blogs/@blog.Id"
|
||||||
|
hx-swap="outerHTML"
|
||||||
|
hx-target="#file-list">
|
||||||
|
[ Delete ]
|
||||||
|
</a>
|
||||||
|
<a class="pico-color-blue-100" target="_blank" href="/edit/@blog.Id">[ Edit ]</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<hr/>
|
||||||
|
}
|
||||||
|
</body>
|
||||||
|
<footer>
|
||||||
|
<div>
|
||||||
|
<button
|
||||||
|
hx-get="/edit-list?offset=@(Model.Offset - 25)"
|
||||||
|
hx-swap="outerHTML"
|
||||||
|
hx-target="#file-list"
|
||||||
|
@PropertyHelper.If(Math.Clamp(Model.Offset, 0, Model.Amount) == 0, "disabled")>
|
||||||
|
Previous
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
hx-get="/edit-list?offset=@(Model.Offset + 25)"
|
||||||
|
hx-swap="outerHTML"
|
||||||
|
hx-target="#file-list"
|
||||||
|
@PropertyHelper.If(Math.Clamp(Model.Offset, 0, Model.Amount) >= Model.Amount - 25, "disabled")>
|
||||||
|
Next
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
</article>
|
||||||
|
</div>
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
@model FastBlog.Core.Models.Blogs.Blog
|
@model FastBlog.Core.Models.Blogs.Blog
|
||||||
|
|
||||||
@await Html.PartialAsync("Blogs/BlogContent", Model)
|
@await Html.PartialAsync("Blogs/Content", Model)
|
||||||
|
|
||||||
<hr/>
|
<hr/>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
@model FastBlog.Core.Models.Blogs.Blog
|
||||||
|
|
||||||
|
@{
|
||||||
|
ViewBag.Title = Model.Metadata.Title;
|
||||||
|
}
|
||||||
|
|
||||||
|
@if(DateTime.UtcNow < Model.Metadata.CreatedAt)
|
||||||
|
{
|
||||||
|
<div class="alert alert-important">
|
||||||
|
<p class="alert-title">Unpublished blog</p>
|
||||||
|
<p>This blog would not be visible and accessible until @Model.Metadata.CreatedAt.ToString("g")</p>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
@await Html.PartialAsync("Blogs/Content", Model)
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<hr/>
|
||||||
|
@await Html.PartialAsync("Blogs/ManageCard", Model.Metadata)
|
||||||
|
</div>
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
@model FastBlog.Core.Models.Blogs.BlogMeta
|
||||||
|
|
||||||
|
<article>
|
||||||
|
<header>
|
||||||
|
<h3>Editor's controls</h3>
|
||||||
|
</header>
|
||||||
|
<body>
|
||||||
|
<div class="grid">
|
||||||
|
<div>
|
||||||
|
<a href="/edit/@Model.Id">
|
||||||
|
<button class="btn-fw">
|
||||||
|
Edit
|
||||||
|
</button>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<button class="btn-fw secondary" hx-delete="/blogs/@Model.Id">
|
||||||
|
Delete
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</article>
|
||||||
|
|
@ -30,7 +30,7 @@ return;
|
||||||
<nav>
|
<nav>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="~/"><h1>@options.Value.Title</h1></a></li>
|
<li><a href="~/"><h1>@options.Value.Title</h1></a></li>
|
||||||
<li><a href="~/blog/list">Blog</a></li>
|
<li><a href="~/blogs/list">Blog</a></li>
|
||||||
<li><a href="~/edit">New</a></li>
|
<li><a href="~/edit">New</a></li>
|
||||||
<li><a href="~/files">Files</a></li>
|
<li><a href="~/files">Files</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
|
||||||
|
|
@ -63,6 +63,10 @@ h1, h2, h3, h4, h5, h6 {
|
||||||
--pico-font-family: 'Fira Code', Roboto, sans-serif;
|
--pico-font-family: 'Fira Code', Roboto, sans-serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hr {
|
||||||
|
border-color: var(--pico-secondary-background);
|
||||||
|
}
|
||||||
|
|
||||||
a {
|
a {
|
||||||
color: inherit;
|
color: inherit;
|
||||||
text-decoration-color: inherit;
|
text-decoration-color: inherit;
|
||||||
|
|
@ -131,7 +135,7 @@ body {
|
||||||
margin-top: 35px;
|
margin-top: 35px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.markdown-alert {
|
.markdown-alert, .alert {
|
||||||
color: inherit;
|
color: inherit;
|
||||||
background-color: inherit;
|
background-color: inherit;
|
||||||
border-radius: var(--pico-border-radius);
|
border-radius: var(--pico-border-radius);
|
||||||
|
|
@ -141,41 +145,41 @@ body {
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.markdown-alert p {
|
.markdown-alert p, .alert p {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.markdown-alert-title {
|
.markdown-alert-title, .alert-title {
|
||||||
font-family: 'Fira Code', Roboto, sans-serif;
|
font-family: 'Fira Code', Roboto, sans-serif;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
.markdown-alert-note {
|
.markdown-alert-note, .alert-note {
|
||||||
color: var(--pico-primary);
|
color: var(--pico-primary);
|
||||||
background: var(--pico-primary-background);
|
background: var(--pico-primary-background);
|
||||||
border-color: var(--pico-primary-background);
|
border-color: var(--pico-primary-background);
|
||||||
}
|
}
|
||||||
|
|
||||||
.markdown-alert-tip {
|
.markdown-alert-tip, .alert-tip {
|
||||||
color: var(--pico-tip);
|
color: var(--pico-tip);
|
||||||
background: var(--pico-tip-background);
|
background: var(--pico-tip-background);
|
||||||
border-color: var(--pico-tip-background);
|
border-color: var(--pico-tip-background);
|
||||||
}
|
}
|
||||||
|
|
||||||
.markdown-alert-important {
|
.markdown-alert-important, .alert-important {
|
||||||
color: var(--pico-important);
|
color: var(--pico-important);
|
||||||
background: var(--pico-important-background);
|
background: var(--pico-important-background);
|
||||||
border-color: var(--pico-important-background);
|
border-color: var(--pico-important-background);
|
||||||
}
|
}
|
||||||
|
|
||||||
.markdown-alert-warning {
|
.markdown-alert-warning, .alert-warning {
|
||||||
color: var(--pico-warning);
|
color: var(--pico-warning);
|
||||||
background: var(--pico-warning-background);
|
background: var(--pico-warning-background);
|
||||||
border-color: var(--pico-warning-background);
|
border-color: var(--pico-warning-background);
|
||||||
}
|
}
|
||||||
|
|
||||||
.markdown-alert-caution {
|
.markdown-alert-caution, .alert-caution {
|
||||||
color: var(--pico-danger);
|
color: var(--pico-danger);
|
||||||
background: var(--pico-danger-background);
|
background: var(--pico-danger-background);
|
||||||
border-color: var(--pico-danger-background);
|
border-color: var(--pico-danger-background);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue