housekeeping updates #7
24 changed files with 367 additions and 334 deletions
|
@ -13,4 +13,6 @@ jobs:
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- name: docker build
|
- name: docker build
|
||||||
run: docker build -t nseguin42/website:${{ github.sha }} .
|
run: docker build -t nseguin42/website:${{ github.sha }} .
|
||||||
|
- name: cleanup old images
|
||||||
|
run: docker image prune -f --filter "until=24h"
|
|
@ -1,19 +1,30 @@
|
||||||
<!DOCTYPE html>
|
@using Microsoft.AspNetCore.Mvc.ViewFeatures
|
||||||
|
@using JetBrains.Annotations
|
||||||
|
@inject IFileVersionProvider FileVersionProvider
|
||||||
|
|
||||||
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
|
<!--suppress HtmlRequiredTitleElement -->
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8"/>
|
<meta charset="utf-8"/>
|
||||||
<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="@PathBase"/>
|
||||||
<link rel="stylesheet" href="css/styles.css" asp-append-version="true"/>
|
<link rel="stylesheet" href="@AddVersionToPath("css/styles.css")"/>
|
||||||
<link rel="stylesheet" href="app.css"/>
|
<link rel="stylesheet" href="@AddVersionToPath("app.css")"/>
|
||||||
<link rel="stylesheet" href="NSeguin.Dev.Web.styles.css"/>
|
|
||||||
<link rel="icon" type="image/png" href="favicon.ico"/>
|
<link rel="icon" type="image/png" href="favicon.ico"/>
|
||||||
<HeadOutlet/>
|
<HeadOutlet/>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<Routes/>
|
<Routes/>
|
||||||
|
@* ReSharper disable once Html.PathError *@
|
||||||
<script src="_framework/blazor.web.js"></script>
|
<script src="_framework/blazor.web.js"></script>
|
||||||
<script src="js/app.js"></script>
|
<script src="@AddVersionToPath("js/app.js")"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
||||||
|
@code {
|
||||||
|
private const string PathBase = "/";
|
||||||
|
|
||||||
|
private string AddVersionToPath([PathReference] string path) => FileVersionProvider.AddFileVersionToPath(PathBase, path);
|
||||||
|
}
|
|
@ -1,15 +1,26 @@
|
||||||
@inherits LayoutComponentBase
|
@inherits LayoutComponentBase
|
||||||
|
|
||||||
<div class="page">
|
<div class="fixed inset-y-0 right-0 left-[40rem] hidden lg:block xl:left-[50rem] z-0">
|
||||||
<main>
|
<svg
|
||||||
<article class="content px-4">
|
viewBox="0 0 1080 957"
|
||||||
@Body
|
fill="none"
|
||||||
</article>
|
aria-hidden="true"
|
||||||
</main>
|
class="absolute inset-0 h-full w-full"
|
||||||
|
preserveAspectRatio="xMinYMid slice">
|
||||||
|
<path fill="#2e3440" d="M0 0h1080v957H0z"/>
|
||||||
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="blazor-error-ui">
|
<main>
|
||||||
An unhandled error has occurred.
|
<div class="px-4 py-10 sm:py-28 sm:px-6 lg:px-8 xl:py-32 xl:px-28">
|
||||||
<a href="" class="reload">Reload</a>
|
<div class="mx-auto max-w-xl lg:mx-0">
|
||||||
<a class="dismiss">🗙</a>
|
<article class="px-4">
|
||||||
</div>
|
<ErrorBoundary>
|
||||||
|
@Body
|
||||||
|
</ErrorBoundary>
|
||||||
|
</article>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<BlazorErrorUI/>
|
|
@ -1,92 +0,0 @@
|
||||||
.page {
|
|
||||||
position: relative;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
main {
|
|
||||||
flex: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.top-row {
|
|
||||||
background-color: #f7f7f7;
|
|
||||||
border-bottom: 1px solid #d6d5d5;
|
|
||||||
justify-content: flex-end;
|
|
||||||
height: 3.5rem;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.top-row ::deep a, .top-row ::deep .btn-link {
|
|
||||||
white-space: nowrap;
|
|
||||||
margin-left: 1.5rem;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.top-row ::deep a:hover, .top-row ::deep .btn-link:hover {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
.top-row ::deep a:first-child {
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 640.98px) {
|
|
||||||
.top-row {
|
|
||||||
justify-content: space-between;
|
|
||||||
}
|
|
||||||
|
|
||||||
.top-row ::deep a, .top-row ::deep .btn-link {
|
|
||||||
margin-left: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (min-width: 641px) {
|
|
||||||
.page {
|
|
||||||
flex-direction: row;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar {
|
|
||||||
width: 250px;
|
|
||||||
height: 100vh;
|
|
||||||
position: sticky;
|
|
||||||
top: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.top-row {
|
|
||||||
position: sticky;
|
|
||||||
top: 0;
|
|
||||||
z-index: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.top-row.auth ::deep a:first-child {
|
|
||||||
flex: 1;
|
|
||||||
text-align: right;
|
|
||||||
width: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.top-row, article {
|
|
||||||
padding-left: 2rem !important;
|
|
||||||
padding-right: 1.5rem !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#blazor-error-ui {
|
|
||||||
background: lightyellow;
|
|
||||||
bottom: 0;
|
|
||||||
box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
|
|
||||||
display: none;
|
|
||||||
left: 0;
|
|
||||||
padding: 0.6rem 1.25rem 0.7rem 1.25rem;
|
|
||||||
position: fixed;
|
|
||||||
width: 100%;
|
|
||||||
z-index: 1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
#blazor-error-ui .dismiss {
|
|
||||||
cursor: pointer;
|
|
||||||
position: absolute;
|
|
||||||
right: 0.75rem;
|
|
||||||
top: 0.5rem;
|
|
||||||
}
|
|
65
src/NSeguin.Dev.Web/Components/Pages/Attributions.razor
Normal file
65
src/NSeguin.Dev.Web/Components/Pages/Attributions.razor
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
@page "/attributions"
|
||||||
|
@using System.Text.Json
|
||||||
|
|
||||||
|
<PageTitle>Attributions</PageTitle>
|
||||||
|
|
||||||
|
<h1 class="mt-4 text-4xl md:text-5xl lg:text-6xl font-extrabold text-[2rem] leading-10 tracking-tighter">
|
||||||
|
Attributions
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
<p class="mt-4 text-base text-slate-900">
|
||||||
|
The source code for this website is available on
|
||||||
|
<a href="https://www.git.nseguin.dev/nseguin/website" class="text-blue-600">Forgejo (git.nseguin.dev).</a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p class="mt-4 text-base text-slate-900">
|
||||||
|
It is licensed under the <a href="@LicenseUrl" class="text-blue-600">MIT License</a>.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<ul class="list-disc mt-4 text-base leading-7 text-slate-900">
|
||||||
|
@if (AttributionsList != null)
|
||||||
|
{
|
||||||
|
@foreach (var attribution in AttributionsList)
|
||||||
|
{
|
||||||
|
<li class="mt-4" key="@attribution.Name">
|
||||||
|
<h2 class="text-lg font-bold">@attribution.Name</h2>
|
||||||
|
@if (!string.IsNullOrWhiteSpace(attribution.Url?.ToString()))
|
||||||
|
{
|
||||||
|
<p class="mt-2">URL: <a href="@attribution.Url.ToString()" class="text-blue-600">@attribution.Url</a></p>
|
||||||
|
}
|
||||||
|
@if (attribution.Authors?.Any() ?? false)
|
||||||
|
{
|
||||||
|
<p class="mt-2">Author(s): @string.Join(", ", attribution.Authors)</p>
|
||||||
|
}
|
||||||
|
@if (!string.IsNullOrWhiteSpace(attribution.License))
|
||||||
|
{
|
||||||
|
<p class="mt-2">License: <a href="@attribution.LicenseUrl?.ToString()" class="text-blue-600">@attribution.License</a></p>
|
||||||
|
}
|
||||||
|
</li>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
@code {
|
||||||
|
|
||||||
|
public record Attribution(string Name, Uri Url, string? License, Uri? LicenseUrl, string[]? Authors);
|
||||||
|
|
||||||
|
private string? AttributionsJson { get; set; }
|
||||||
|
|
||||||
|
private List<Attribution>? AttributionsList { get; set; }
|
||||||
|
|
||||||
|
private string? LicenseUrl => "static/LICENSE.txt";
|
||||||
|
|
||||||
|
[Inject]
|
||||||
|
private IWebHostEnvironment HostEnvironment { get; set; }
|
||||||
|
|
||||||
|
protected override async Task OnInitializedAsync()
|
||||||
|
{
|
||||||
|
var attributionsFile = HostEnvironment.WebRootFileProvider.GetFileInfo("static/attributions.json");
|
||||||
|
using var reader = new StreamReader(attributionsFile.CreateReadStream());
|
||||||
|
AttributionsJson = await reader.ReadToEndAsync();
|
||||||
|
AttributionsList = JsonSerializer.Deserialize<List<Attribution>>(AttributionsJson);
|
||||||
|
await base.OnInitializedAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,42 +0,0 @@
|
||||||
@page "/authentication/{action}"
|
|
||||||
@using System.Security.Claims
|
|
||||||
|
|
||||||
@code{
|
|
||||||
private const string Login = "login";
|
|
||||||
private const string Logout = "logout";
|
|
||||||
public ClaimsPrincipal? User { get; private set; }
|
|
||||||
|
|
||||||
[CascadingParameter]
|
|
||||||
public required Task<AuthenticationState> AuthenticationState { get; set; }
|
|
||||||
|
|
||||||
[Parameter]
|
|
||||||
public string? Action { get; set; }
|
|
||||||
|
|
||||||
[Inject]
|
|
||||||
public required NavigationManager NavigationManager { get; set; }
|
|
||||||
|
|
||||||
private void SignOut()
|
|
||||||
{
|
|
||||||
NavigationManager.NavigateTo("MicrosoftIdentity/Account/SignOut", true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SignIn()
|
|
||||||
{
|
|
||||||
NavigationManager.NavigateTo("MicrosoftIdentity/Account/SignIn", true);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
|
||||||
{
|
|
||||||
var authenticationState = await AuthenticationState;
|
|
||||||
User = authenticationState.User;
|
|
||||||
if (Action == Logout)
|
|
||||||
{
|
|
||||||
SignOut();
|
|
||||||
}
|
|
||||||
else if (Action == Login)
|
|
||||||
{
|
|
||||||
SignIn();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,40 +1,49 @@
|
||||||
@page "/Error"
|
@page "/Error"
|
||||||
@using System.Diagnostics
|
@using System.Diagnostics
|
||||||
|
@using Microsoft.AspNetCore.Diagnostics
|
||||||
|
|
||||||
<PageTitle>Error</PageTitle>
|
<PageTitle>Error</PageTitle>
|
||||||
|
|
||||||
<h1 class="text-danger">Error.</h1>
|
<h1 class="mt-4 text-4xl md:text-5xl lg:text-6xl font-semibold text-[2rem] leading-10 tracking-tighter">Error</h1>
|
||||||
<h2 class="text-danger">An error occurred while processing your request.</h2>
|
|
||||||
|
<p class="text-slate text-xl mt-4">
|
||||||
|
An error occurred while processing your request.
|
||||||
|
</p>
|
||||||
|
|
||||||
@if (ShowRequestId)
|
@if (ShowRequestId)
|
||||||
{
|
{
|
||||||
<p>
|
<p class="text-slate text-md mt-4 mb-4">
|
||||||
<strong>Request ID:</strong> <code>@RequestId</code>
|
<strong>Request ID:</strong> <code>@RequestId</code>
|
||||||
</p>
|
</p>
|
||||||
}
|
}
|
||||||
|
|
||||||
<h3>Development Mode</h3>
|
@if (ShowException)
|
||||||
<p>
|
{
|
||||||
Swapping to <strong>Development</strong> environment will display more detailed information about the error that occurred.
|
<p class="text-slate mt-4 mb-4">
|
||||||
</p>
|
<h2 class="text-2xl font-bold">Exception</h2>
|
||||||
<p>
|
<pre class="text-md">
|
||||||
<strong>The Development environment shouldn't be enabled for deployed applications.</strong>
|
<code>@(Exception?.ToString())</code>
|
||||||
It can result in displaying sensitive information from exceptions to end users.
|
</pre>
|
||||||
For local debugging, enable the <strong>Development</strong> environment by setting the <strong>ASPNETCORE_ENVIRONMENT</strong> environment variable to <strong>Development</strong>
|
</p>
|
||||||
and restarting the app.
|
}
|
||||||
</p>
|
|
||||||
|
|
||||||
@code{
|
@code{
|
||||||
|
|
||||||
[CascadingParameter]
|
[CascadingParameter]
|
||||||
private HttpContext? HttpContext { get; set; }
|
private HttpContext? HttpContext { get; set; }
|
||||||
|
|
||||||
|
[Inject]
|
||||||
|
private IHostEnvironment HostEnvironment { get; set; } = default!;
|
||||||
|
|
||||||
|
private Exception? Exception { get; set; }
|
||||||
private string? RequestId { get; set; }
|
private string? RequestId { get; set; }
|
||||||
private bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
|
private bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
|
||||||
|
private bool ShowException => Exception is not null && HostEnvironment.IsDevelopment();
|
||||||
|
|
||||||
protected override void OnInitialized()
|
protected override void OnInitialized()
|
||||||
{
|
{
|
||||||
RequestId = Activity.Current?.Id ?? HttpContext?.TraceIdentifier;
|
RequestId = Activity.Current?.Id ?? HttpContext?.TraceIdentifier;
|
||||||
|
Exception = HttpContext?.Features.Get<IExceptionHandlerFeature>()?.Error ?? new Exception("An error occurred while processing your request.");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,84 +1,68 @@
|
||||||
@page "/"
|
@page "/"
|
||||||
@using NSeguin.Dev.Web.Components.Shared.HeroIcons
|
@using NSeguin.Dev.Web.Components.Shared.HeroIcons
|
||||||
@layout SimpleLayout
|
|
||||||
@rendermode InteractiveServer
|
@rendermode InteractiveServer
|
||||||
|
|
||||||
<PageTitle>Home</PageTitle>
|
<PageTitle>Home</PageTitle>
|
||||||
|
|
||||||
<div class="fixed inset-y-0 right-0 left-[40rem] hidden lg:block xl:left-[50rem] z-0">
|
<p class="mt-10 flex items-center text-sm font-semibold leading-6 text-brand">
|
||||||
<svg
|
<a href="https://git.nseguin.dev/nseguin/website">nseguin/website</a>
|
||||||
viewBox="0 0 1080 957"
|
<small class="ml-3 rounded-full bg-brand/5 px-2 text-[0.8125rem] font-medium leading-6">
|
||||||
fill="none"
|
</small>
|
||||||
aria-hidden="true"
|
</p>
|
||||||
class="absolute inset-0 h-full w-full"
|
|
||||||
preserveAspectRatio="xMinYMid slice">
|
|
||||||
<path fill="#2e3440" d="M0 0h1080v957H0z"/>
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="px-4 py-10 sm:py-28 sm:px-6 lg:px-8 xl:py-32 xl:px-28">
|
<h1 class="mt-4 text-4xl md:text-5xl lg:text-6xl font-extrabold text-[2rem] leading-10 tracking-tighter">
|
||||||
<div class="mx-auto max-w-xl lg:mx-0">
|
Nick Seguin
|
||||||
<h1 class="mt-10 flex items-center text-sm font-semibold leading-6 text-brand">
|
</h1>
|
||||||
<a href="https://git.nseguin.dev/nseguin/website">nseguin/website</a>
|
|
||||||
<small class="ml-3 rounded-full bg-brand/5 px-2 text-[0.8125rem] font-medium leading-6">
|
|
||||||
</small>
|
|
||||||
</h1>
|
|
||||||
|
|
||||||
<h1 class="mt-4 text-4xl md:text-5xl lg:text-6xl font-extrabold text-[2rem] leading-10 tracking-tighter">
|
<p class="mt-4 text-base leading-7 text-slate-900">
|
||||||
Nick Seguin
|
I'm a software developer based in Iowa.
|
||||||
</h1>
|
I'm currently working on a few projects, including this website.
|
||||||
|
Thanks for visiting!
|
||||||
|
</p>
|
||||||
|
|
||||||
<p class="mt-4 text-base leading-7 text-slate-900">
|
<div class="flex">
|
||||||
I'm a software developer based in Iowa.
|
<div class="w-full sm:w-auto">
|
||||||
I'm currently working on a few projects, including this website.
|
<div class="mt-10 grid grid-cols-1 gap-x-6 gap-y-4 sm:grid-cols-3">
|
||||||
Thanks for visiting!
|
<a
|
||||||
</p>
|
href="/resume"
|
||||||
|
class="group relative rounded-2xl px-6 py-4 text-sm font-semibold leading-6 text-nord-1 sm:py-6">
|
||||||
<div class="flex">
|
<span class="absolute inset-0 rounded-2xl bg-slate-50 transition group-hover:bg-slate-100 sm:group-hover:scale-105">
|
||||||
<div class="w-full sm:w-auto">
|
</span>
|
||||||
<div class="mt-10 grid grid-cols-1 gap-x-6 gap-y-4 sm:grid-cols-3">
|
<span class="relative flex items-center gap-4 sm:flex-col">
|
||||||
<a
|
<div class="w-6 h-6">
|
||||||
href="/resume"
|
<HeroIcon Kind="HeroIcon.DocumentText"/>
|
||||||
class="group relative rounded-2xl px-6 py-4 text-sm font-semibold leading-6 text-nord-1 sm:py-6">
|
</div>
|
||||||
<span class="absolute inset-0 rounded-2xl bg-slate-50 transition group-hover:bg-slate-100 sm:group-hover:scale-105">
|
Resumé
|
||||||
</span>
|
</span>
|
||||||
<span class="relative flex items-center gap-4 sm:flex-col">
|
</a>
|
||||||
<div class="w-6 h-6">
|
<a
|
||||||
<HeroIcon Kind="HeroIcon.DocumentText"/>
|
href="https://github.com/nseguin42"
|
||||||
</div>
|
class="group relative rounded-2xl px-6 py-4 text-sm font-semibold leading-6 text-nord-1 sm:py-6">
|
||||||
Resumé
|
<span class="absolute inset-0 rounded-2xl bg-slate-50 transition group-hover:bg-slate-100 sm:group-hover:scale-105">
|
||||||
</span>
|
</span>
|
||||||
</a>
|
<span class="relative flex items-center gap-4 sm:flex-col">
|
||||||
<a
|
<svg viewBox="0 0 24 24" aria-hidden="true" class="h-6 w-6">
|
||||||
href="https://github.com/nseguin42"
|
<path
|
||||||
class="group relative rounded-2xl px-6 py-4 text-sm font-semibold leading-6 text-nord-1 sm:py-6">
|
fill-rule="evenodd"
|
||||||
<span class="absolute inset-0 rounded-2xl bg-slate-50 transition group-hover:bg-slate-100 sm:group-hover:scale-105">
|
clip-rule="evenodd"
|
||||||
</span>
|
d="M12 0C5.37 0 0 5.506 0 12.303c0 5.445 3.435 10.043 8.205 11.674.6.107.825-.262.825-.585 0-.292-.015-1.261-.015-2.291C6 21.67 5.22 20.346 4.98 19.654c-.135-.354-.72-1.446-1.23-1.738-.42-.23-1.02-.8-.015-.815.945-.015 1.62.892 1.845 1.261 1.08 1.86 2.805 1.338 3.495 1.015.105-.8.42-1.338.765-1.645-2.67-.308-5.46-1.37-5.46-6.075 0-1.338.465-2.446 1.23-3.307-.12-.308-.54-1.569.12-3.26 0 0 1.005-.323 3.3 1.26.96-.276 1.98-.415 3-.415s2.04.139 3 .416c2.295-1.6 3.3-1.261 3.3-1.261.66 1.691.24 2.952.12 3.26.765.861 1.23 1.953 1.23 3.307 0 4.721-2.805 5.767-5.475 6.075.435.384.81 1.122.81 2.276 0 1.645-.015 2.968-.015 3.383 0 .323.225.707.825.585a12.047 12.047 0 0 0 5.919-4.489A12.536 12.536 0 0 0 24 12.304C24 5.505 18.63 0 12 0Z"
|
||||||
<span class="relative flex items-center gap-4 sm:flex-col">
|
fill="#18181B"/>
|
||||||
<svg viewBox="0 0 24 24" aria-hidden="true" class="h-6 w-6">
|
</svg>
|
||||||
<path
|
GitHub
|
||||||
fill-rule="evenodd"
|
</span>
|
||||||
clip-rule="evenodd"
|
</a>
|
||||||
d="M12 0C5.37 0 0 5.506 0 12.303c0 5.445 3.435 10.043 8.205 11.674.6.107.825-.262.825-.585 0-.292-.015-1.261-.015-2.291C6 21.67 5.22 20.346 4.98 19.654c-.135-.354-.72-1.446-1.23-1.738-.42-.23-1.02-.8-.015-.815.945-.015 1.62.892 1.845 1.261 1.08 1.86 2.805 1.338 3.495 1.015.105-.8.42-1.338.765-1.645-2.67-.308-5.46-1.37-5.46-6.075 0-1.338.465-2.446 1.23-3.307-.12-.308-.54-1.569.12-3.26 0 0 1.005-.323 3.3 1.26.96-.276 1.98-.415 3-.415s2.04.139 3 .416c2.295-1.6 3.3-1.261 3.3-1.261.66 1.691.24 2.952.12 3.26.765.861 1.23 1.953 1.23 3.307 0 4.721-2.805 5.767-5.475 6.075.435.384.81 1.122.81 2.276 0 1.645-.015 2.968-.015 3.383 0 .323.225.707.825.585a12.047 12.047 0 0 0 5.919-4.489A12.536 12.536 0 0 0 24 12.304C24 5.505 18.63 0 12 0Z"
|
<a
|
||||||
fill="#18181B"/>
|
href="mailto:mail@nseguin.dev"
|
||||||
</svg>
|
class="group relative rounded-2xl px-6 py-4 text-sm font-semibold leading-6 text-nord-1 sm:py-6">
|
||||||
GitHub
|
<span class="absolute inset-0 rounded-2xl bg-slate-50 transition group-hover:bg-slate-100 sm:group-hover:scale-105">
|
||||||
</span>
|
</span>
|
||||||
</a>
|
<span class="relative flex items-center gap-4 sm:flex-col text-black">
|
||||||
<a
|
<div class="w-6 h-6">
|
||||||
href="mailto:mail@nseguin.dev"
|
<HeroIcon Kind="HeroIcon.Envelope"/>
|
||||||
class="group relative rounded-2xl px-6 py-4 text-sm font-semibold leading-6 text-nord-1 sm:py-6">
|
</div>
|
||||||
<span class="absolute inset-0 rounded-2xl bg-slate-50 transition group-hover:bg-slate-100 sm:group-hover:scale-105">
|
Contact
|
||||||
</span>
|
</span>
|
||||||
<span class="relative flex items-center gap-4 sm:flex-col text-black">
|
</a>
|
||||||
<div class="w-6 h-6">
|
|
||||||
<HeroIcon Kind="HeroIcon.Envelope"/>
|
|
||||||
</div>
|
|
||||||
Contact
|
|
||||||
</span>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
|
@ -1,34 +1,17 @@
|
||||||
@page "/NotFound"
|
@page "/NotFound"
|
||||||
@using Microsoft.AspNetCore.WebUtilities
|
@using Microsoft.AspNetCore.WebUtilities
|
||||||
@layout SimpleLayout
|
|
||||||
@inject NavigationManager NavigationManager
|
@inject NavigationManager NavigationManager
|
||||||
|
|
||||||
<PageTitle>Not Found</PageTitle>
|
<PageTitle>Not Found</PageTitle>
|
||||||
|
|
||||||
<div class="fixed inset-y-0 right-0 left-[40rem] hidden lg:block xl:left-[50rem] z-0">
|
<h1 class="mt-4 text-4xl md:text-5xl lg:text-6xl font-semibold text-[2rem] leading-10 tracking-tighter">Not Found</h1>
|
||||||
<svg
|
<p class="text-slate text-xl mt-4">
|
||||||
viewBox="0 0 1080 957"
|
No page was found at <code>@Path</code>.
|
||||||
fill="none"
|
</p>
|
||||||
aria-hidden="true"
|
|
||||||
class="absolute inset-0 h-full w-full"
|
|
||||||
preserveAspectRatio="xMinYMid slice">
|
|
||||||
<path fill="#2e3440" d="M0 0h1080v957H0z"/>
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="px-4 py-10 sm:py-28 sm:px-6 lg:px-8 xl:py-32 xl:px-28">
|
<p class="text-blue-600 text-xl mt-4">
|
||||||
<div class="mx-auto max-w-xl lg:mx-0">
|
<a href="/" aria-label="Home" class="underline">Go to home page</a>
|
||||||
<h1 class="mt-4 text-4xl md:text-5xl lg:text-6xl font-semibold text-[2rem] leading-10 tracking-tighter">Not Found</h1>
|
</p>
|
||||||
<p class="text-slate text-xl mt-4">
|
|
||||||
No page was found at <code>@Path</code>.<br/>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p class="text-blue-600 text-xl mt-4">
|
|
||||||
<a href="/" aria-label="Home" class="underline">Go to home page</a>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
private string Path { get; set; }
|
private string Path { get; set; }
|
||||||
|
|
|
@ -1,24 +1,5 @@
|
||||||
<CascadingAuthenticationState>
|
<Router AppAssembly="@typeof(Program).Assembly" AdditionalAssemblies="new[] {typeof(Client._Imports).Assembly, typeof(AsyncEventHandler).Assembly}">
|
||||||
<Router AppAssembly="@typeof(Program).Assembly" AdditionalAssemblies="new[] {typeof(Client._Imports).Assembly}">
|
<Found Context="routeData">
|
||||||
<Found Context="routeData">
|
<RouteView RouteData="@routeData" DefaultLayout="@typeof(SimpleLayout)"/>
|
||||||
<AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(SimpleLayout)">
|
</Found>
|
||||||
<NotAuthorized>
|
</Router>
|
||||||
@if (context.User.Identity?.IsAuthenticated != true)
|
|
||||||
{
|
|
||||||
<RedirectToLogin/>
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
<p role="alert">You are not authorized to access this resource.</p>
|
|
||||||
}
|
|
||||||
</NotAuthorized>
|
|
||||||
</AuthorizeRouteView>
|
|
||||||
</Found>
|
|
||||||
<NotFound>
|
|
||||||
<PageTitle>Not found</PageTitle>
|
|
||||||
<LayoutView Layout="@typeof(SimpleLayout)">
|
|
||||||
<p role="alert">Sorry, there's nothing at this address.</p>
|
|
||||||
</LayoutView>
|
|
||||||
</NotFound>
|
|
||||||
</Router>
|
|
||||||
</CascadingAuthenticationState>
|
|
|
@ -1,14 +1,21 @@
|
||||||
@inject IJSRuntime JSRuntime
|
@inject IJSRuntime JSRuntime
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public Func<ElementReference> GetControl { get; set; }
|
public Func<ElementReference>? GetControl { get; set; }
|
||||||
|
|
||||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||||
{
|
{
|
||||||
if (GetControl is null)
|
if (GetControl is null)
|
||||||
|
{
|
||||||
throw new ArgumentNullException(nameof(GetControl));
|
throw new ArgumentNullException(nameof(GetControl));
|
||||||
|
}
|
||||||
|
|
||||||
if (firstRender)
|
if (firstRender)
|
||||||
|
{
|
||||||
await JSRuntime.InvokeVoidAsync("App.scrollIntoView", GetControl(), true);
|
await JSRuntime.InvokeVoidAsync("App.scrollIntoView", GetControl(), true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
11
src/NSeguin.Dev.Web/Components/Shared/BlazorErrorUI.razor
Normal file
11
src/NSeguin.Dev.Web/Components/Shared/BlazorErrorUI.razor
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
@inject IHostEnvironment HostEnvironment
|
||||||
|
|
||||||
|
<div id="blazor-error-ui"
|
||||||
|
class="bg-yellow-400 bottom-0 shadow-md fixed left-0 py-2 px-4 w-full z-50 hidden"
|
||||||
|
role="alertdialog"
|
||||||
|
tabindex="-1"
|
||||||
|
data-nosnippet>
|
||||||
|
An unhandled error has occurred.
|
||||||
|
<a href="#" class="reload underline">Reload</a>
|
||||||
|
<button class="dismiss" type="button">🗙</button>
|
||||||
|
</div>
|
|
@ -1,20 +0,0 @@
|
||||||
@inject NavigationManager Navigation
|
|
||||||
|
|
||||||
<AuthorizeView>
|
|
||||||
<Authorized>
|
|
||||||
Hello, @context.User.Identity?.Name!
|
|
||||||
<button class="nav-link btn btn-link" @onclick="BeginLogout">Log out</button>
|
|
||||||
</Authorized>
|
|
||||||
<NotAuthorized>
|
|
||||||
<a href="authentication/login">Log in</a>
|
|
||||||
</NotAuthorized>
|
|
||||||
</AuthorizeView>
|
|
||||||
|
|
||||||
@code{
|
|
||||||
|
|
||||||
private void BeginLogout(MouseEventArgs args)
|
|
||||||
{
|
|
||||||
Navigation.NavigateTo("authentication/logout");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,10 +0,0 @@
|
||||||
@inject NavigationManager Navigation
|
|
||||||
|
|
||||||
@code {
|
|
||||||
|
|
||||||
protected override void OnInitialized()
|
|
||||||
{
|
|
||||||
Navigation.NavigateTo($"authentication/login?returnUrl={Uri.EscapeDataString(Navigation.Uri)}");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -38,6 +38,12 @@
|
||||||
<AdditionalFiles Include="pnpm-lock.yaml" CopyToOutputDirectory="Always"/>
|
<AdditionalFiles Include="pnpm-lock.yaml" CopyToOutputDirectory="Always"/>
|
||||||
<Content Remove="libman.json"/>
|
<Content Remove="libman.json"/>
|
||||||
<AdditionalFiles Include="libman.json" CopyToOutputDirectory="Always"/>
|
<AdditionalFiles Include="libman.json" CopyToOutputDirectory="Always"/>
|
||||||
|
<Content Update="wwwroot\static\attributions.json">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Update="wwwroot\static\LICENSE.txt">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
2
src/NSeguin.Dev.Web/NSeguin.Dev.Web.csproj.DotSettings
Normal file
2
src/NSeguin.Dev.Web/NSeguin.Dev.Web.csproj.DotSettings
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||||
|
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=components_005Cmodels/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
|
|
@ -1,6 +1,8 @@
|
||||||
using Azure.Identity;
|
using Azure.Identity;
|
||||||
|
|
||||||
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
|
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.Extensions.FileProviders;
|
||||||
using Microsoft.Identity.Web;
|
using Microsoft.Identity.Web;
|
||||||
using Microsoft.Identity.Web.UI;
|
using Microsoft.Identity.Web.UI;
|
||||||
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
|
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
|
||||||
|
@ -30,6 +32,20 @@ builder.Services.AddRazorComponents()
|
||||||
.AddInteractiveServerComponents()
|
.AddInteractiveServerComponents()
|
||||||
.AddInteractiveWebAssemblyComponents();
|
.AddInteractiveWebAssemblyComponents();
|
||||||
|
|
||||||
|
builder.Services.AddProblemDetails(
|
||||||
|
options =>
|
||||||
|
{
|
||||||
|
options.CustomizeProblemDetails = ctx =>
|
||||||
|
{
|
||||||
|
ctx.ProblemDetails.Extensions.TryAdd("traceId", ctx.HttpContext.TraceIdentifier);
|
||||||
|
if (ctx.HttpContext.RequestServices.GetRequiredService<IHostEnvironment>()
|
||||||
|
.IsDevelopment())
|
||||||
|
{
|
||||||
|
ctx.ProblemDetails.Extensions.TryAdd("exception", ctx.Exception?.ToString());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
if (builder.Environment.IsStaging() || builder.Environment.IsProduction())
|
if (builder.Environment.IsStaging() || builder.Environment.IsProduction())
|
||||||
{
|
{
|
||||||
builder.Configuration.AddAzureAppConfiguration(
|
builder.Configuration.AddAzureAppConfiguration(
|
||||||
|
@ -97,14 +113,21 @@ app.UseAuthorization();
|
||||||
app.UseAntiforgery();
|
app.UseAntiforgery();
|
||||||
app.MapRazorComponents<App>()
|
app.MapRazorComponents<App>()
|
||||||
.AddAdditionalAssemblies(typeof(Counter).Assembly)
|
.AddAdditionalAssemblies(typeof(Counter).Assembly)
|
||||||
|
.AddAdditionalAssemblies(typeof(AsyncEventHandler).Assembly)
|
||||||
.AddInteractiveServerRenderMode()
|
.AddInteractiveServerRenderMode()
|
||||||
.AddInteractiveWebAssemblyRenderMode();
|
.AddInteractiveWebAssemblyRenderMode();
|
||||||
|
|
||||||
app.MapControllers();
|
app.UseExceptionHandler();
|
||||||
app.MapFallback(
|
app.MapFallback(
|
||||||
ctx =>
|
ctx =>
|
||||||
{
|
{
|
||||||
ctx.Response.Redirect($"/NotFound?path={ctx.Request.Path}");
|
ctx.Response.StatusCode = StatusCodes.Status404NotFound;
|
||||||
|
var headers = ctx.Request.GetTypedHeaders();
|
||||||
|
if (headers.Accept.Any(h => h.MatchesMediaType("text/html")))
|
||||||
|
{
|
||||||
|
ctx.Response.Redirect($"/NotFound?path={ctx.Request.Path}");
|
||||||
|
}
|
||||||
|
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
"name": "nseguin.dev.web",
|
"name": "nseguin.dev.web",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"bun-types": "latest"
|
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"typescript": "^5.0.0"
|
"typescript": "^5.0.0"
|
||||||
|
@ -12,7 +11,11 @@
|
||||||
"css:watch": "pnpm tailwindcss -i ./wwwroot/css/site.css -o ./wwwroot/css/styles.css -c ./tailwind.config.ts --watch"
|
"css:watch": "pnpm tailwindcss -i ./wwwroot/css/site.css -o ./wwwroot/css/styles.css -c ./tailwind.config.ts --watch"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"tailwind-nord": "^1.3.0",
|
"tailwindcss": "^3.4.1",
|
||||||
"tailwindcss": "^3.4.1"
|
"@tailwindcss/typography": "^0.5.10",
|
||||||
|
"@tailwindcss/forms": "^0.5.7",
|
||||||
|
"@tailwindcss/aspect-ratio": "^0.4.2",
|
||||||
|
"@tailwindcss/container-queries": "^0.1.1",
|
||||||
|
"tailwind-nord": "^1.3.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -5,6 +5,18 @@ settings:
|
||||||
excludeLinksFromLockfile: false
|
excludeLinksFromLockfile: false
|
||||||
|
|
||||||
dependencies:
|
dependencies:
|
||||||
|
'@tailwindcss/aspect-ratio':
|
||||||
|
specifier: ^0.4.2
|
||||||
|
version: 0.4.2(tailwindcss@3.4.1)
|
||||||
|
'@tailwindcss/container-queries':
|
||||||
|
specifier: ^0.1.1
|
||||||
|
version: 0.1.1(tailwindcss@3.4.1)
|
||||||
|
'@tailwindcss/forms':
|
||||||
|
specifier: ^0.5.7
|
||||||
|
version: 0.5.7(tailwindcss@3.4.1)
|
||||||
|
'@tailwindcss/typography':
|
||||||
|
specifier: ^0.5.10
|
||||||
|
version: 0.5.10(tailwindcss@3.4.1)
|
||||||
tailwind-nord:
|
tailwind-nord:
|
||||||
specifier: ^1.3.0
|
specifier: ^1.3.0
|
||||||
version: 1.3.0
|
version: 1.3.0
|
||||||
|
@ -15,11 +27,6 @@ dependencies:
|
||||||
specifier: ^5.0.0
|
specifier: ^5.0.0
|
||||||
version: 5.3.3
|
version: 5.3.3
|
||||||
|
|
||||||
devDependencies:
|
|
||||||
bun-types:
|
|
||||||
specifier: latest
|
|
||||||
version: 1.0.15
|
|
||||||
|
|
||||||
packages:
|
packages:
|
||||||
|
|
||||||
/@alloc/quick-lru@5.2.0:
|
/@alloc/quick-lru@5.2.0:
|
||||||
|
@ -78,6 +85,43 @@ packages:
|
||||||
fastq: 1.15.0
|
fastq: 1.15.0
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/@tailwindcss/aspect-ratio@0.4.2(tailwindcss@3.4.1):
|
||||||
|
resolution: {integrity: sha512-8QPrypskfBa7QIMuKHg2TA7BqES6vhBrDLOv8Unb6FcFyd3TjKbc6lcmb9UPQHxfl24sXoJ41ux/H7qQQvfaSQ==}
|
||||||
|
peerDependencies:
|
||||||
|
tailwindcss: '>=2.0.0 || >=3.0.0 || >=3.0.0-alpha.1'
|
||||||
|
dependencies:
|
||||||
|
tailwindcss: 3.4.1
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@tailwindcss/container-queries@0.1.1(tailwindcss@3.4.1):
|
||||||
|
resolution: {integrity: sha512-p18dswChx6WnTSaJCSGx6lTmrGzNNvm2FtXmiO6AuA1V4U5REyoqwmT6kgAsIMdjo07QdAfYXHJ4hnMtfHzWgA==}
|
||||||
|
peerDependencies:
|
||||||
|
tailwindcss: '>=3.2.0'
|
||||||
|
dependencies:
|
||||||
|
tailwindcss: 3.4.1
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@tailwindcss/forms@0.5.7(tailwindcss@3.4.1):
|
||||||
|
resolution: {integrity: sha512-QE7X69iQI+ZXwldE+rzasvbJiyV/ju1FGHH0Qn2W3FKbuYtqp8LKcy6iSw79fVUT5/Vvf+0XgLCeYVG+UV6hOw==}
|
||||||
|
peerDependencies:
|
||||||
|
tailwindcss: '>=3.0.0 || >= 3.0.0-alpha.1'
|
||||||
|
dependencies:
|
||||||
|
mini-svg-data-uri: 1.4.4
|
||||||
|
tailwindcss: 3.4.1
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@tailwindcss/typography@0.5.10(tailwindcss@3.4.1):
|
||||||
|
resolution: {integrity: sha512-Pe8BuPJQJd3FfRnm6H0ulKIGoMEQS+Vq01R6M5aCrFB/ccR/shT+0kXLjouGC1gFLm9hopTFN+DMP0pfwRWzPw==}
|
||||||
|
peerDependencies:
|
||||||
|
tailwindcss: '>=3.0.0 || insiders'
|
||||||
|
dependencies:
|
||||||
|
lodash.castarray: 4.4.0
|
||||||
|
lodash.isplainobject: 4.0.6
|
||||||
|
lodash.merge: 4.6.2
|
||||||
|
postcss-selector-parser: 6.0.10
|
||||||
|
tailwindcss: 3.4.1
|
||||||
|
dev: false
|
||||||
|
|
||||||
/any-promise@1.3.0:
|
/any-promise@1.3.0:
|
||||||
resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==}
|
resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==}
|
||||||
dev: false
|
dev: false
|
||||||
|
@ -117,10 +161,6 @@ packages:
|
||||||
fill-range: 7.0.1
|
fill-range: 7.0.1
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/bun-types@1.0.15:
|
|
||||||
resolution: {integrity: sha512-XkEvWLV1JIhcVIpf2Lu6FXnZUxRUkQVJmgY+VT7os6Tk5X1nkXx11q4Rtu6txsqpDJZfUeZXblnnD59K+6wsVA==}
|
|
||||||
dev: true
|
|
||||||
|
|
||||||
/camelcase-css@2.0.1:
|
/camelcase-css@2.0.1:
|
||||||
resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==}
|
resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==}
|
||||||
engines: {node: '>= 6'}
|
engines: {node: '>= 6'}
|
||||||
|
@ -296,6 +336,18 @@ packages:
|
||||||
resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
|
resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/lodash.castarray@4.4.0:
|
||||||
|
resolution: {integrity: sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/lodash.isplainobject@4.0.6:
|
||||||
|
resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/lodash.merge@4.6.2:
|
||||||
|
resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/merge2@1.4.1:
|
/merge2@1.4.1:
|
||||||
resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
|
resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
|
||||||
engines: {node: '>= 8'}
|
engines: {node: '>= 8'}
|
||||||
|
@ -309,6 +361,11 @@ packages:
|
||||||
picomatch: 2.3.1
|
picomatch: 2.3.1
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/mini-svg-data-uri@1.4.4:
|
||||||
|
resolution: {integrity: sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==}
|
||||||
|
hasBin: true
|
||||||
|
dev: false
|
||||||
|
|
||||||
/minimatch@3.1.2:
|
/minimatch@3.1.2:
|
||||||
resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
|
resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -427,6 +484,14 @@ packages:
|
||||||
postcss-selector-parser: 6.0.13
|
postcss-selector-parser: 6.0.13
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/postcss-selector-parser@6.0.10:
|
||||||
|
resolution: {integrity: sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==}
|
||||||
|
engines: {node: '>=4'}
|
||||||
|
dependencies:
|
||||||
|
cssesc: 3.0.0
|
||||||
|
util-deprecate: 1.0.2
|
||||||
|
dev: false
|
||||||
|
|
||||||
/postcss-selector-parser@6.0.13:
|
/postcss-selector-parser@6.0.13:
|
||||||
resolution: {integrity: sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==}
|
resolution: {integrity: sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==}
|
||||||
engines: {node: '>=4'}
|
engines: {node: '>=4'}
|
||||||
|
|
|
@ -145,7 +145,11 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
require('tailwind-nord')
|
require('tailwind-nord'),
|
||||||
|
require('@tailwindcss/typography'),
|
||||||
|
require('@tailwindcss/forms'),
|
||||||
|
require('@tailwindcss/aspect-ratio'),
|
||||||
|
require('@tailwindcss/container-queries')
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
} satisfies Config
|
} satisfies Config
|
File diff suppressed because one or more lines are too long
|
@ -1,9 +1,15 @@
|
||||||
var App = App || {};
|
const App = App || {};
|
||||||
|
|
||||||
App.setFocus = function (element) {
|
App.setFocus = function (element) {
|
||||||
element.focus();
|
element.focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
App.scrollIntoView = function (element, args) {
|
App.scrollIntoView = function (element, args) {
|
||||||
|
if (element === undefined) {
|
||||||
|
console.error('Element is undefined');
|
||||||
|
} else if (element === null) {
|
||||||
|
console.error('Element is null');
|
||||||
|
}
|
||||||
|
|
||||||
element.scrollIntoView(args);
|
element.scrollIntoView(args);
|
||||||
}
|
}
|
22
src/NSeguin.Dev.Web/wwwroot/static/LICENSE.txt
Normal file
22
src/NSeguin.Dev.Web/wwwroot/static/LICENSE.txt
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2023 Nicholas Seguin
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
|
2
src/NSeguin.Dev.Web/wwwroot/static/attributions.json
Normal file
2
src/NSeguin.Dev.Web/wwwroot/static/attributions.json
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
[
|
||||||
|
]
|
Loading…
Reference in a new issue