up
This commit is contained in:
parent
f622fbcf0a
commit
9ef06db411
12
App.razor
12
App.razor
@ -1,12 +1,12 @@
|
||||
<CascadingState>
|
||||
<CascadingAuthenticationState>
|
||||
<CascadingAuthenticationState>
|
||||
<CascadingState>
|
||||
<Router AppAssembly="@typeof(App).Assembly">
|
||||
<Found Context="routeData">
|
||||
<AuthorizeRouteView DefaultLayout="@typeof(MainLayout)" RouteData="@routeData">
|
||||
<NotAuthorized>
|
||||
@if (context.User.Identity?.IsAuthenticated != true)
|
||||
{
|
||||
<RedirectToLogin/>
|
||||
<RedirectToLogin />
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -14,7 +14,7 @@
|
||||
}
|
||||
</NotAuthorized>
|
||||
</AuthorizeRouteView>
|
||||
<FocusOnNavigate RouteData="@routeData" Selector="section"/>
|
||||
<FocusOnNavigate RouteData="@routeData" Selector="section" />
|
||||
</Found>
|
||||
<NotFound>
|
||||
<Title>Not found</Title>
|
||||
@ -23,5 +23,5 @@
|
||||
</LayoutView>
|
||||
</NotFound>
|
||||
</Router>
|
||||
</CascadingAuthenticationState>
|
||||
</CascadingState>
|
||||
</CascadingState>
|
||||
</CascadingAuthenticationState>
|
@ -1,4 +1,6 @@
|
||||
<section class="flex flex-col space-y-4">
|
||||
@inherits LocalizableComponentBase
|
||||
|
||||
<section class="flex flex-col space-y-4">
|
||||
|
||||
@if (isPosting)
|
||||
{
|
||||
@ -22,7 +24,7 @@
|
||||
ValueChanged="async v => await OnTimelineChange(v)" ValueExpression="() => Filters.TimelineType">
|
||||
@foreach (var timelineType in Enum.GetValues<TimelineType>())
|
||||
{
|
||||
<option value="@timelineType">@CascadingState.Localizer[timelineType.ToString()]</option>
|
||||
<option value="@timelineType">@Localizer[timelineType.ToString()]</option>
|
||||
}
|
||||
</InputSelect>
|
||||
</span>
|
||||
@ -39,7 +41,7 @@
|
||||
ValueChanged="async v => await OnTimeSortChange(v)" ValueExpression="() => Filters.TimeSortingType">
|
||||
@foreach (var timeSortingType in Enum.GetValues<TimeSortingType>())
|
||||
{
|
||||
<option value="@timeSortingType">@CascadingState.Localizer[timeSortingType.ToString()]</option>
|
||||
<option value="@timeSortingType">@Localizer[timeSortingType.ToString()]</option>
|
||||
}
|
||||
</InputSelect>
|
||||
</span>
|
||||
@ -56,7 +58,7 @@
|
||||
<span class="icon is-left">
|
||||
<i class="ion-md-create"></i>
|
||||
</span>
|
||||
<span>@CascadingState.Localizer["Post"]</span>
|
||||
<span>@Localizer["Post"]</span>
|
||||
</button>
|
||||
</div>
|
||||
}
|
||||
|
@ -1,4 +1,6 @@
|
||||
<div class="flex space-x-3 w-full neomorph is-nxxsmall rounded-xl @CssContainer">
|
||||
@inherits LocalizableComponentBase
|
||||
|
||||
<div class="flex space-x-3 w-full neomorph is-nxxsmall rounded-xl @CssContainer">
|
||||
|
||||
<div class="flex flex-col py-3 pl-3 md:py-4 md:pl-4 flex-none rounded-l-xl bg-cover bg-no-repeat bg-center"
|
||||
style="background-image:linear-gradient(to left, var(--background), transparent), url('@(Message.User?.BackgroundUrl)');">
|
||||
@ -17,7 +19,7 @@
|
||||
<p class="inline-flex flex-1 space-x-2 min-w-0 text-xs text-xs">
|
||||
<a class="font-bold" href="@Message.BoostingUser.ProfileUrl" title="@Message.BoostingUser.UserName">@Message.BoostingUser.DisplayName</a>
|
||||
<i class="ion-md-repeat has-text-info" aria-hidden="true"></i>
|
||||
<span>@CascadingState.Localizer["boosted"]</span>
|
||||
<span>@Localizer["boosted"]</span>
|
||||
</p>
|
||||
}
|
||||
<p class="inline-flex flex-1 space-x-2 min-w-0 justify-between text-xs md:text-sm">
|
||||
@ -31,10 +33,10 @@
|
||||
</span>
|
||||
<span class="flex-none inline-flex space-x-1 items-center">
|
||||
<span title="@Message.CreatedAt.ToLocalTime().ToString("📅dd/MM/yy 🕒HH:mm")">
|
||||
@Message.CreatedAt.GetPassedTime(CascadingState.Localizer)
|
||||
@Message.CreatedAt.GetPassedTime(Localizer._pLocalizer)
|
||||
</span>
|
||||
<i aria-hidden="true" class="@Message.MessageType.GetMessageTypeIcon() text-md"
|
||||
title="@CascadingState.Localizer[Message.MessageType.ToString()]">
|
||||
title="@Localizer[Message.MessageType.ToString()]">
|
||||
</i>
|
||||
</span>
|
||||
</p>
|
||||
@ -105,7 +107,7 @@
|
||||
@if (OnMessageReply.HasDelegate)
|
||||
{
|
||||
<button class="button is-small is-rounded @(isAnswering ? "neoBtnSmallInsetPlain" : "neoBtnSmall")" @onclick="Reply"
|
||||
title="@CascadingState.Localizer[isAnswering ? "Close" : "Reply"]">
|
||||
title="@Localizer[isAnswering ? "Close" : "Reply"]">
|
||||
<span class="icon">
|
||||
<i aria-hidden="true" class="@SUtility.IfTrueThen(isAnswering, "ion-md-close-circle", "ion-md-text") text-lg has-text-success"></i>
|
||||
</span>
|
||||
@ -114,7 +116,7 @@
|
||||
@if (OnMessageBoost.HasDelegate)
|
||||
{
|
||||
<button class="button is-small is-rounded @SUtility.IfTrueThen(Message.IsBoostedByCurrentUser,"neoBtnSmallInsetPlain","neoBtnSmall") @SUtility.IfTrueThen(Message.BoostsCounter != 0, "has-icons-left")" @onclick="() => OnMessageBoost.InvokeAsync(Message)"
|
||||
title="@CascadingState.Localizer["Boost"]">
|
||||
title="@Localizer["Boost"]">
|
||||
<span class="icon is-left">
|
||||
<i aria-hidden="true" class="ion-md-repeat @SUtility.IfTrueThen(Message.BoostsCounter != 0,null,"text-lg") has-text-info"></i>
|
||||
</span>
|
||||
@ -127,7 +129,7 @@
|
||||
@if (OnMessageFavourite.HasDelegate)
|
||||
{
|
||||
<button class="button is-small is-rounded @SUtility.IfTrueThen(Message.IsFavourite, "neoBtnSmallInsetPlain", "neoBtnSmall")" @onclick="() => OnMessageFavourite.InvokeAsync(Message)"
|
||||
title="@CascadingState.Localizer["Favourite"]">
|
||||
title="@Localizer["Favourite"]">
|
||||
<span class="icon">
|
||||
<i aria-hidden="true" class="@SUtility.IfTrueThen(Message.IsFavourite, "ion-md-heart-dislike", "ion-md-heart") text-lg text-pink-300"></i>
|
||||
</span>
|
||||
@ -139,7 +141,7 @@
|
||||
<DropdownButton IsOpen="Message.IsOptionsOpen">
|
||||
<DropdownTrigger>
|
||||
<button class="button is-small is-rounded neoBtnSmall" @onclick="() => Message.IsOptionsOpen = !Message.IsOptionsOpen"
|
||||
title="@CascadingState.Localizer["Other"]">
|
||||
title="@Localizer["Other"]">
|
||||
<span class="icon">
|
||||
<i aria-hidden="true" class="ion-md-more text-lg"></i>
|
||||
</span>
|
||||
@ -153,7 +155,7 @@
|
||||
<span class="icon is-left">
|
||||
<i aria-hidden="true" class="ion-md-paper-plane text-base has-text-success"></i>
|
||||
</span>
|
||||
<span>@CascadingState.Localizer["Direct message"]</span>
|
||||
<span>@Localizer["Direct message"]</span>
|
||||
</button>
|
||||
</div>
|
||||
}
|
||||
@ -164,7 +166,7 @@
|
||||
<span class="icon is-left">
|
||||
<i aria-hidden="true" class="ion-md-eye-off text-base drop-shadow has-text-warning"></i>
|
||||
</span>
|
||||
<span>@CascadingState.Localizer["Mute"]</span>
|
||||
<span>@Localizer["Mute"]</span>
|
||||
</button>
|
||||
</div>
|
||||
}
|
||||
@ -175,7 +177,7 @@
|
||||
<span class="icon is-left">
|
||||
<i aria-hidden="true" class="ion-md-remove-circle text-base has-text-danger"></i>
|
||||
</span>
|
||||
<span>@CascadingState.Localizer["Block"]</span>
|
||||
<span>@Localizer["Block"]</span>
|
||||
</button>
|
||||
</div>
|
||||
}
|
||||
@ -183,11 +185,11 @@
|
||||
{
|
||||
<div class="dropdown-item">
|
||||
<button class="button is-small has-icons-left is-rounded neoBtnSmall" @onclick="DeleteMessage"
|
||||
title="@CascadingState.Localizer["Delete"]">
|
||||
title="@Localizer["Delete"]">
|
||||
<span class="icon is-left">
|
||||
<i aria-hidden="true" class="ion-md-trash text-lg has-text-danger"></i>
|
||||
</span>
|
||||
<span>@CascadingState.Localizer["Delete"]</span>
|
||||
<span>@Localizer["Delete"]</span>
|
||||
</button>
|
||||
</div>
|
||||
}
|
||||
@ -196,7 +198,7 @@
|
||||
@if (IncludeExpand)
|
||||
{
|
||||
<NavLink class="button is-small is-rounded neoBtnSmall" href="@($"expand/{Message.MessageId}")"
|
||||
title="@CascadingState.Localizer["Expand"]">
|
||||
title="@Localizer["Expand"]">
|
||||
<span class="icon">
|
||||
<i aria-hidden="true" class="ion-md-expand text-lg"></i>
|
||||
</span>
|
||||
|
@ -1,13 +1,10 @@
|
||||
<p class="w-full loadAnimation text-center">
|
||||
@inherits LocalizableComponentBase
|
||||
<p class="w-full loadAnimation text-center">
|
||||
<span>.</span>
|
||||
<span>.</span>
|
||||
<span>.</span>
|
||||
@CascadingState.Localizer["loading"]
|
||||
@Localizer["loading"]
|
||||
<span>.</span>
|
||||
<span>.</span>
|
||||
<span>.</span>
|
||||
</p>
|
||||
|
||||
@code {
|
||||
[CascadingParameter] CascadingState CascadingState { get; set; }
|
||||
}
|
@ -1,10 +1,12 @@
|
||||
<EditForm Model="MessageForm" OnValidSubmit="OnValidSubmit">
|
||||
@inherits LocalizableComponentBase
|
||||
|
||||
<EditForm Model="MessageForm" OnValidSubmit="OnValidSubmit">
|
||||
<DataAnnotationsValidator />
|
||||
|
||||
<div class="field mb-3">
|
||||
<div class="control">
|
||||
<InputText class="input rounded-t-[1.4rem] rounded-b-lg neoInput" maxlength="64"
|
||||
placeholder="@CascadingState.Localizer["Title (optional)"]" Value="@MessageForm.Title"
|
||||
placeholder="@Localizer["Title (optional)"]" Value="@MessageForm.Title"
|
||||
ValueChanged="(v) => OnTitleChanged(v)"
|
||||
ValueExpression="() => MessageForm.Title" />
|
||||
</div>
|
||||
@ -12,7 +14,7 @@
|
||||
<textarea @bind="@MessageForm.Content" @bind:event="oninput"
|
||||
class="textarea rounded-b-[1.4rem] rounded-t-lg neoInput"
|
||||
maxlength="5000"
|
||||
placeholder="@CascadingState.Localizer["oh shit... here we go again"]" rows="3"></textarea>
|
||||
placeholder="@Localizer["oh shit... here we go again"]" rows="3"></textarea>
|
||||
<span class="absolute text-xs opacity-50 right-2 bottom-1">@(MessageForm.Content?.Length ?? 0)/5000</span>
|
||||
</div>
|
||||
@if (showPreviewButton && isPreviewOpen && MessageForm.Content is { Length: > 0 })
|
||||
@ -52,7 +54,7 @@
|
||||
<i class="ion-md-image"></i> <b>@media.FileName</b>
|
||||
</p>
|
||||
<p class="text-xs break-all">
|
||||
<i class="ion-md-code"></i> @media.ContentType <i class="ion-md-fitness"></i> @media.Size.GetFileSize(CascadingState.Localizer)
|
||||
<i class="ion-md-code"></i> @media.ContentType <i class="ion-md-fitness"></i> @media.Size.GetFileSize(Localizer._pLocalizer)
|
||||
</p>
|
||||
</div>
|
||||
<button class="button is-small is-rounded self-start neoBtnSmall" @onclick="() => RemoveFile(media)" type="button">
|
||||
@ -64,7 +66,7 @@
|
||||
<div class="field w-full">
|
||||
<div class="control w-full">
|
||||
<InputTextArea @bind-Value="media.AltText" class="textarea w-full is-small !rounded-lg neoInput"
|
||||
placeholder="@CascadingState.Localizer["Alternative text"]" rows="1" />
|
||||
placeholder="@Localizer["Alternative text"]" rows="1" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -81,7 +83,7 @@
|
||||
<b>@media.FileName</b>
|
||||
</p>
|
||||
<p class="text-xs break-all">
|
||||
<i class="ion-md-code"></i> @media.ContentType <i class="ion-md-fitness"></i> @media.Size.GetFileSize(CascadingState.Localizer)
|
||||
<i class="ion-md-code"></i> @media.ContentType <i class="ion-md-fitness"></i> @media.Size.GetFileSize(Localizer._pLocalizer)
|
||||
</p>
|
||||
</div>
|
||||
<button class="button is-small is-rounded neoBtnSmall" @onclick="() => RemoveFile(media)" type="button">
|
||||
@ -101,7 +103,7 @@
|
||||
<b>@media.FileName</b>
|
||||
</p>
|
||||
<p class="text-xs break-all">
|
||||
<i class="ion-md-code"></i> @media.ContentType <i class="ion-md-fitness"></i> @media.Size.GetFileSize(CascadingState.Localizer)
|
||||
<i class="ion-md-code"></i> @media.ContentType <i class="ion-md-fitness"></i> @media.Size.GetFileSize(Localizer._pLocalizer)
|
||||
</p>
|
||||
<audio controls="controls" class="w-full max-h-8">
|
||||
<source src="@media.Base64Preview" type="@media.ContentType">
|
||||
@ -131,7 +133,7 @@
|
||||
<DropdownButton CssDirection="is-left" IsOpen="MessageForm.IsScopeOptionsOpen">
|
||||
<DropdownTrigger>
|
||||
<button class="button is-small is-rounded @SUtility.IfTrueThen(MessageForm.IsScopeOptionsOpen, "neoBtnSmallInsetPlain", "neoBtnSmall")" @onclick="OpenCloseMessageType"
|
||||
title="@string.Format(CascadingState.Localizer["Message scope type: {0}"], CascadingState.Localizer[MessageType.Direct.ToString()])" type="button">
|
||||
title="@string.Format(Localizer["Message scope type: {0}"], Localizer[MessageType.Direct.ToString()])" type="button">
|
||||
<span class="icon">
|
||||
<i class="@MessageForm.MessageType.GetMessageTypeIcon() text-base"></i>
|
||||
</span>
|
||||
@ -140,25 +142,25 @@
|
||||
<DropdownContent>
|
||||
<div class="flex space-x-3 px-2">
|
||||
<button class="button is-small is-rounded @SUtility.IfTrueThen(MessageForm.MessageType is MessageType.Direct, "neoBtnSmallInsetPlain", "neoBtnSmall")" @onclick="() => UpdateMessageType(MessageType.Direct)"
|
||||
title="@CascadingState.Localizer[MessageType.Direct.ToString()]" type="button">
|
||||
title="@Localizer[MessageType.Direct.ToString()]" type="button">
|
||||
<span class="icon">
|
||||
<i class="ion-md-paper-plane text-base"></i>
|
||||
</span>
|
||||
</button>
|
||||
<button class="button is-small is-rounded @SUtility.IfTrueThen(MessageForm.MessageType is MessageType.FollowersOnly, "neoBtnSmallInsetPlain", "neoBtnSmall")" @onclick="() => UpdateMessageType(MessageType.FollowersOnly)"
|
||||
title="@CascadingState.Localizer[MessageType.FollowersOnly.ToString()]" type="button">
|
||||
title="@Localizer[MessageType.FollowersOnly.ToString()]" type="button">
|
||||
<span class="icon">
|
||||
<i class="ion-md-lock text-base"></i>
|
||||
</span>
|
||||
</button>
|
||||
<button class="button is-small is-rounded @SUtility.IfTrueThen(MessageForm.MessageType is MessageType.Unlisted, "neoBtnSmallInsetPlain", "neoBtnSmall")" @onclick="() => UpdateMessageType(MessageType.Unlisted)"
|
||||
title="@CascadingState.Localizer[MessageType.Unlisted.ToString()]" type="button">
|
||||
title="@Localizer[MessageType.Unlisted.ToString()]" type="button">
|
||||
<span class="icon">
|
||||
<i class="ion-md-unlock text-base"></i>
|
||||
</span>
|
||||
</button>
|
||||
<button class="button is-small is-rounded @SUtility.IfTrueThen(MessageForm.MessageType is MessageType.Public, "neoBtnSmallInsetPlain", "neoBtnSmall")" @onclick="() => UpdateMessageType(MessageType.Public)"
|
||||
title="@CascadingState.Localizer[MessageType.Public.ToString()]" type="button">
|
||||
title="@Localizer[MessageType.Public.ToString()]" type="button">
|
||||
<span class="icon">
|
||||
<i class="ion-md-globe text-base"></i>
|
||||
</span>
|
||||
@ -188,7 +190,7 @@
|
||||
<InputSelect TValue="MediaType" Value="MessageForm.MediaType" ValueChanged="v => OnMediaTypeChanged(v)" ValueExpression="() => MessageForm.MediaType" disabled="@(MessageForm.Media.Count > 0)">
|
||||
@foreach (var mediaType in Enum.GetValues<MediaType>())
|
||||
{
|
||||
<option value="@mediaType">@CascadingState.Localizer[mediaType.ToString()]</option>
|
||||
<option value="@mediaType">@Localizer[mediaType.ToString()]</option>
|
||||
}
|
||||
</InputSelect>
|
||||
</div>
|
||||
@ -204,7 +206,7 @@
|
||||
<InputSelect TValue="ContentType" Value="MessageForm.ContentType" ValueChanged="v => OnContentTypeChanged(v)" ValueExpression="() => MessageForm.ContentType">
|
||||
@foreach (var contentType in Enum.GetValues<ContentType>())
|
||||
{
|
||||
<option value="@contentType">@CascadingState.Localizer[contentType.ToString()]</option>
|
||||
<option value="@contentType">@Localizer[contentType.ToString()]</option>
|
||||
}
|
||||
</InputSelect>
|
||||
</div>
|
||||
@ -220,7 +222,7 @@
|
||||
@if (showPreviewButton)
|
||||
{
|
||||
<button class="button is-small is-rounded @SUtility.IfTrueThen(isPreviewOpen, "neoBtnSmallInsetPlain", "neoBtnSmall")" @onclick="OnOpenClosePreview"
|
||||
title="@CascadingState.Localizer["Show preview"]" type="button">
|
||||
title="@Localizer["Show preview"]" type="button">
|
||||
<span class="icon">
|
||||
<i class="@SUtility.IfTrueThen(isPreviewOpen, "ion-md-eye-off", "ion-md-eye") text-base"></i>
|
||||
</span>
|
||||
@ -232,7 +234,7 @@
|
||||
<div class="flex space-x-3">
|
||||
|
||||
<button class="button is-small is-rounded has-icons-right neoBtnSmall" type="submit">
|
||||
<span>@CascadingState.Localizer["Post"]</span>
|
||||
<span>@Localizer["Post"]</span>
|
||||
<span class="icon is-right">
|
||||
<i class="ion-md-send"></i>
|
||||
</span>
|
||||
@ -312,12 +314,12 @@
|
||||
};
|
||||
if (eventArgs.FileCount > maximumFileCount)
|
||||
{
|
||||
fileInputErrorMessage = string.Format(CascadingState.Localizer["The maximum number of files accepted is {0}, but {1} were supplied."], maximumFileCount, eventArgs.FileCount);
|
||||
fileInputErrorMessage = string.Format(Localizer["The maximum number of files accepted is {0}, but {1} were supplied."], maximumFileCount, eventArgs.FileCount);
|
||||
return;
|
||||
}
|
||||
if (eventArgs.FileCount + MessageForm.Media.Count > maximumFileCount)
|
||||
{
|
||||
fileInputErrorMessage = string.Format(CascadingState.Localizer["The maximum number of files accepted is {0}, but {1} were supplied."], maximumFileCount, $"{MessageForm.Media.Count}+{eventArgs.FileCount}");
|
||||
fileInputErrorMessage = string.Format(Localizer["The maximum number of files accepted is {0}, but {1} were supplied."], maximumFileCount, $"{MessageForm.Media.Count}+{eventArgs.FileCount}");
|
||||
return;
|
||||
}
|
||||
var maxAllowedSize = MessageForm.MediaType switch
|
||||
@ -336,7 +338,7 @@
|
||||
if (MessageForm.Media.Any(m => m.FileName == file.Name)) continue;
|
||||
if (file.Size > maxAllowedSize)
|
||||
{
|
||||
fileInputErrorMessage += string.Format(CascadingState.Localizer["Supplied file \"{0}\" with size {1:N0}MBs exceeds the maximum of {2:N0}MBs."], file.Name, file.Size / 1_048_576, maxAllowedSize / 1_048_576) + "<br/>";
|
||||
fileInputErrorMessage += string.Format(Localizer["Supplied file \"{0}\" with size {1:N0}MBs exceeds the maximum of {2:N0}MBs."], file.Name, file.Size / 1_048_576, maxAllowedSize / 1_048_576) + "<br/>";
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -423,7 +425,7 @@
|
||||
contentError = default;
|
||||
if ((MessageForm.Content is { Length: 0 } && MessageForm.Media.Count == 0))
|
||||
{
|
||||
contentError = CascadingState.Localizer["Missing content, either message or media"];
|
||||
contentError = Localizer["Missing content, either message or media"];
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1,14 +0,0 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
|
||||
|
||||
namespace decePubClient.Extensions
|
||||
{
|
||||
public class CustomAuthenticationMessageHandler : AuthorizationMessageHandler
|
||||
{
|
||||
public CustomAuthenticationMessageHandler(IAccessTokenProvider provider, NavigationManager navigation)
|
||||
: base(provider, navigation)
|
||||
{
|
||||
ConfigureHandler(new string[] { "https://demo.identityserver.io" });
|
||||
}
|
||||
}
|
||||
}
|
153
Extensions/ExtensionMethods.cs
Normal file
153
Extensions/ExtensionMethods.cs
Normal file
@ -0,0 +1,153 @@
|
||||
using Blazored.LocalStorage;
|
||||
|
||||
using collAnon.Client.Services;
|
||||
|
||||
using decePubClient.Models;
|
||||
using decePubClient.Services;
|
||||
|
||||
using Markdig;
|
||||
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
|
||||
|
||||
using SocialPub.ClientModels;
|
||||
|
||||
using System.Collections.Specialized;
|
||||
using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
using System.Text.Json;
|
||||
using System.Web;
|
||||
|
||||
namespace decePubClient.Extensions
|
||||
{
|
||||
public static class ExtensionMethods
|
||||
{
|
||||
#region Navigation Manager
|
||||
|
||||
public static NameValueCollection QueryString(this NavigationManager navigationManager) =>
|
||||
HttpUtility.ParseQueryString(new Uri(navigationManager.Uri).Query);
|
||||
|
||||
public static string QueryString(this NavigationManager navigationManager, string key) =>
|
||||
navigationManager.QueryString()[key];
|
||||
|
||||
public static T QueryString<T>(this NavigationManager navigationManager, string key)
|
||||
{
|
||||
var value = navigationManager.QueryString()[key];
|
||||
var converter = TypeDescriptor.GetConverter(typeof(T));
|
||||
if (converter.IsValid(value))
|
||||
return (T)Convert.ChangeType(value, typeof(T));
|
||||
else
|
||||
return default;
|
||||
}
|
||||
|
||||
#endregion Navigation Manager
|
||||
|
||||
#region Setups
|
||||
|
||||
public static async Task SetDefaultCulture(this WebAssemblyHost host)
|
||||
{
|
||||
var culture = default(CultureInfo);
|
||||
try
|
||||
{
|
||||
var storage = host.Services.GetRequiredService<ILocalStorageService>();
|
||||
var publicCache = await storage.GetItemAsync<PublicCacheData>(nameof(PublicCacheData));
|
||||
if (publicCache is null)
|
||||
{
|
||||
publicCache = new();
|
||||
var status = host.Services.GetRequiredService<AppStatusService>();
|
||||
var browserLanguage = status.Language();
|
||||
if (browserLanguage.Contains("en"))
|
||||
browserLanguage = "en-GB";
|
||||
var appConfig = host.Services.GetRequiredService<AppConfiguration>();
|
||||
if (!string.IsNullOrEmpty(publicCache.PageSettings.CurrentLanguageCode) &&
|
||||
publicCache.PageSettings.CurrentLanguageCode.Contains("en"))
|
||||
publicCache.PageSettings.CurrentLanguageCode = "en-GB";
|
||||
culture = new(publicCache.PageSettings.CurrentLanguageCode ?? browserLanguage);
|
||||
publicCache.PageSettings.CurrentLanguageCode = culture.TwoLetterISOLanguageName;
|
||||
await storage.SetItemAsync(nameof(PublicCacheData), publicCache);
|
||||
}
|
||||
|
||||
culture ??= new(publicCache.PageSettings.CurrentLanguageCode == "en" ? "en-GB" : publicCache.PageSettings.CurrentLanguageCode);
|
||||
CultureInfo.DefaultThreadCurrentCulture = culture;
|
||||
CultureInfo.DefaultThreadCurrentUICulture = culture;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine(ex);
|
||||
culture = new("en-GB");
|
||||
CultureInfo.DefaultThreadCurrentCulture = culture;
|
||||
CultureInfo.DefaultThreadCurrentUICulture = culture;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Setups
|
||||
|
||||
public static string GetLogLevelClass(this string logType) => logType switch
|
||||
{
|
||||
"Debug" => "has-text-grey",
|
||||
"Information" => "has-text-info",
|
||||
"Warning" => "has-text-warning-dark",
|
||||
"Error" => "has-text-danger",
|
||||
"Fatal" => "has-text-danger-dark",
|
||||
_ => string.Empty
|
||||
};
|
||||
|
||||
|
||||
#region Formats
|
||||
|
||||
public static MarkdownPipeline Pipeline =>
|
||||
new MarkdownPipelineBuilder().UseGenericAttributes().Build();
|
||||
|
||||
public static string ToJson(this object value) =>
|
||||
JsonSerializer.Serialize(value);
|
||||
|
||||
public static string ToBase64PngImage(this string base64Image) =>
|
||||
$"data:image/png;base64,{base64Image}";
|
||||
|
||||
#endregion Formats
|
||||
|
||||
#region Models
|
||||
|
||||
public static string ToString(this WebResult webResult, CoalescingStringLocalizer localizer) =>
|
||||
localizer["{0} - {1}", webResult.StatusCode, webResult.ErrorMessage];
|
||||
|
||||
public static string Timeframe(this DateTime creationDate, CoalescingStringLocalizer localizer)
|
||||
{
|
||||
var timeframe = DateTime.Now - creationDate.ToLocalTime();
|
||||
switch ((int)timeframe.TotalHours)
|
||||
{
|
||||
case >= 24:
|
||||
return localizer["{0} day/s", (int)timeframe.TotalDays];
|
||||
|
||||
case >= 1 and < 24:
|
||||
return localizer["{0} hour/s", (int)timeframe.TotalHours];
|
||||
|
||||
case 0:
|
||||
return localizer["{0} minute/s", (int)timeframe.TotalMinutes];
|
||||
|
||||
default:
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
public static AuthorizationPolicy IsAdminPolicy() =>
|
||||
new AuthorizationPolicyBuilder().RequireAuthenticatedUser()
|
||||
.RequireClaim(Policies.IsAdmin, true.ToString().ToLower())
|
||||
.RequireClaim(Policies.IsUser, true.ToString().ToLower())
|
||||
.RequireClaim(Policies.IsModerator, true.ToString().ToLower())
|
||||
.Build();
|
||||
|
||||
public static AuthorizationPolicy IsUserPolicy() =>
|
||||
new AuthorizationPolicyBuilder().RequireAuthenticatedUser()
|
||||
.RequireClaim(Policies.IsUser, true.ToString().ToLower())
|
||||
.Build();
|
||||
|
||||
public static AuthorizationPolicy IsUserModeratorPolicy() =>
|
||||
new AuthorizationPolicyBuilder().RequireAuthenticatedUser()
|
||||
.RequireClaim(Policies.IsModerator, true.ToString().ToLower())
|
||||
.Build();
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
@ -25,34 +25,6 @@ namespace decePubClient.Extensions;
|
||||
|
||||
public static class GenericExtensions
|
||||
{
|
||||
public static NameValueCollection QueryString(this NavigationManager navigationManager) =>
|
||||
HttpUtility.ParseQueryString(new Uri(navigationManager.Uri).Query);
|
||||
|
||||
public static string QueryString(this NavigationManager navigationManager, string key) =>
|
||||
navigationManager.QueryString()[key];
|
||||
|
||||
public static T QueryString<T>(this NavigationManager navigationManager, string key)
|
||||
{
|
||||
var value = navigationManager.QueryString()[key];
|
||||
var converter = TypeDescriptor.GetConverter(typeof(T));
|
||||
if (converter.IsValid(value))
|
||||
return (T)Convert.ChangeType(value, typeof(T));
|
||||
else
|
||||
return default;
|
||||
}
|
||||
|
||||
public static async Task SetDefaultCulture(this WebAssemblyHost host)
|
||||
{
|
||||
var storage = host.Services.GetRequiredService<ILocalStorageService>();
|
||||
var language = await storage.GetItemAsync<string>("languageCode");
|
||||
if (language is { Length: 0 })
|
||||
await storage.SetItemAsync("languageCode", language);
|
||||
|
||||
var culture = new CultureInfo(language ??= "en-GB");
|
||||
CultureInfo.DefaultThreadCurrentCulture = culture;
|
||||
CultureInfo.DefaultThreadCurrentUICulture = culture;
|
||||
}
|
||||
|
||||
public static IServiceCollection AddIndexedDb(this IServiceCollection services)
|
||||
{
|
||||
return services.AddIndexedDbDatabase<IndexedDb>(options =>
|
||||
@ -77,7 +49,7 @@ public static class GenericExtensions
|
||||
});
|
||||
}
|
||||
|
||||
public static string GetPassedTime(this DateTime dateTime, IStringLocalizer<AllStrings> localizer)
|
||||
public static string GetPassedTime(this DateTime dateTime, IStringLocalizer localizer)
|
||||
{
|
||||
var timeframe = DateTime.Now - dateTime.ToLocalTime();
|
||||
switch ((int)timeframe.TotalHours)
|
||||
|
@ -1,52 +1,195 @@
|
||||
@if (PublicCacheData != null)
|
||||
{
|
||||
if (PublicCacheData.ThemeIsDarkMode)
|
||||
if (PublicCacheData.PageSettings.ThemeIsDarkMode)
|
||||
{
|
||||
<Meta Content="@($"hsl({PublicCacheData.ThemeIndexColour},16%,12%)")" Name="theme-color"/>
|
||||
<Meta Content="@($"hsl({PublicCacheData.ThemeIndexColour},16%,12%)")" Name="background-color"/>
|
||||
<Meta Content="@($"hsl({PublicCacheData.PageSettings.DarkThemeIndexColour},16%,12%)")" Name="theme-color"/>
|
||||
<Meta Content="@($"hsl({PublicCacheData.PageSettings.DarkThemeIndexColour},16%,12%)")" Name="background-color"/>
|
||||
}
|
||||
else
|
||||
{
|
||||
<Meta Content="@($"hsl({PublicCacheData.ThemeIndexColour},84%,88%)")" Name="theme-color"/>
|
||||
<Meta Content="@($"hsl({PublicCacheData.ThemeIndexColour},84%,88%)")" Name="background-color"/>
|
||||
<Meta Content="@($"hsl({PublicCacheData.PageSettings.LightThemeIndexColour},84%,88%)")" Name="theme-color"/>
|
||||
<Meta Content="@($"hsl({PublicCacheData.PageSettings.LightThemeIndexColour},84%,88%)")" Name="background-color"/>
|
||||
}
|
||||
}
|
||||
<style>
|
||||
:root {
|
||||
@if (PublicCacheData != null)
|
||||
{@if (PublicCacheData.ThemeIsDarkMode)
|
||||
{
|
||||
@($@"--background: hsl({PublicCacheData.ThemeIndexColour},16%,12%);
|
||||
--text-color: hsl({PublicCacheData.ThemeIndexColour},16%,73.6%);
|
||||
--placeholder-text-color: hsla({PublicCacheData.ThemeIndexColour},84%,52.8%,.3);
|
||||
--primary-color: hsl({PublicCacheData.ThemeIndexColour},16%,12%);
|
||||
--primary-color-light: hsl({PublicCacheData.ThemeIndexColour},84%,100%);
|
||||
--primary-color-dark: hsl({PublicCacheData.ThemeIndexColour},16%,33%);
|
||||
--primary-gradiend-light: hsl({PublicCacheData.ThemeIndexColour},16%,16%);
|
||||
--primary-gradiend-dark: hsl({PublicCacheData.ThemeIndexColour},16%,8%);
|
||||
--primary-gradiend-lighter: hsl({PublicCacheData.ThemeIndexColour},16%,20%);
|
||||
--primary-gradiend-darker: hsl({PublicCacheData.ThemeIndexColour},16%,4%);
|
||||
--light-shadow: hsla({PublicCacheData.ThemeIndexColour},84%,66%,.1);
|
||||
--dark-shadow: hsla({PublicCacheData.ThemeIndexColour},16%,1%,.5);")
|
||||
}
|
||||
else
|
||||
{
|
||||
@($@"--background: hsl({PublicCacheData.ThemeIndexColour},84%,88%);
|
||||
--text-color: hsl({PublicCacheData.ThemeIndexColour},84%,26.4%);
|
||||
--placeholder-text-color: hsla({PublicCacheData.ThemeIndexColour},84%,26.4%,.3);
|
||||
--primary-color: hsl({PublicCacheData.ThemeIndexColour},84%,88%);
|
||||
--primary-color-light: hsl({PublicCacheData.ThemeIndexColour},84%,100%);
|
||||
--primary-color-dark: hsl({PublicCacheData.ThemeIndexColour},84%,66%);
|
||||
--primary-gradiend-light: hsl({PublicCacheData.ThemeIndexColour},84%,92%);
|
||||
--primary-gradiend-dark: hsl({PublicCacheData.ThemeIndexColour},84%,84%);
|
||||
--primary-gradiend-lighter: hsl({PublicCacheData.ThemeIndexColour},84%,96%);
|
||||
--primary-gradiend-darker: hsl({PublicCacheData.ThemeIndexColour},84%,80%);
|
||||
--light-shadow: hsla({PublicCacheData.ThemeIndexColour},84%,100%,.5);
|
||||
--dark-shadow: hsla({PublicCacheData.ThemeIndexColour},84%,66%,.5);")
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<HeadContent>
|
||||
|
||||
<style>
|
||||
@if (PublicCacheData != null)
|
||||
{
|
||||
var iconsColour = PublicCacheData.PageSettings.IconsThemeIndexColour is >= 0 and <= 359 ?
|
||||
$"--fa-primary-color: hsl({PublicCacheData.PageSettings.IconsThemeIndexColour},84%,26.4%);--fa-secondary-color: hsl({PublicCacheData.PageSettings.IconsThemeIndexColour},84%,66%);" :
|
||||
PublicCacheData.PageSettings.IconsThemeIndexColour is -2 ?
|
||||
$"--fa-primary-color: hsl(0,0%,1%);--fa-secondary-color: hsl(0,0%,40%);" :
|
||||
$"--fa-primary-color: hsl(0,0%,60%);--fa-secondary-color: hsl(0,0%,99%);";
|
||||
@if (PublicCacheData.PageSettings.PreferSystemTheming)
|
||||
{
|
||||
if (PublicCacheData.PageSettings.ThemeIsDarkGray || PublicCacheData.PageSettings.ThemeIsLightGray)
|
||||
{
|
||||
@($@"@media screen and (prefers-color-scheme: light) {{
|
||||
:root {{
|
||||
--colour-index: 0;
|
||||
--background: hsl(0,0%,88%);
|
||||
--text-color: hsl(0,0%,26.4%);
|
||||
--primary-color: hsl(0,0%,88%);
|
||||
--primary-color-light: hsl(0,0%,100%);
|
||||
--primary-color-dark: hsl(0,0%,66%);
|
||||
--primary-gradiend-light: hsl(0,0%,92%);
|
||||
--primary-gradiend-dark: hsl(0,0%,84%);
|
||||
--primary-gradiend-lighter: hsl(0,0%,96%);
|
||||
--primary-gradiend-darker: hsl(0,0%,80%);
|
||||
--light-shadow: hsla(0,0%,100%, .5);
|
||||
--dark-shadow: hsla(0,0%,66%, .5);
|
||||
--danger-gradiend-light: hsl(0,0%,92%);
|
||||
--danger-gradiend-dark: hsl(0,0%,84%);
|
||||
{iconsColour}
|
||||
}}
|
||||
}}
|
||||
|
||||
@media screen and (prefers-color-scheme: dark) {{
|
||||
:root {{
|
||||
--colour-index: 0;
|
||||
--background: hsl(0,0%,12%);
|
||||
--text-color: hsl(0,0%,73.6%);
|
||||
--primary-color: hsl(0,0%,12%);
|
||||
--primary-color-light: hsl(0,0%,100%);
|
||||
--primary-color-dark: hsl(0,0%,33%);
|
||||
--primary-gradiend-light: hsl(0,0%,16%);
|
||||
--primary-gradiend-dark: hsl(0,0%,8%);
|
||||
--primary-gradiend-lighter: hsl(0,0%,20%);
|
||||
--primary-gradiend-darker: hsl(0,0%,4%);
|
||||
--light-shadow: hsla(0,0%,66%,.1);
|
||||
--dark-shadow: hsla(0,0%,1%,.5);
|
||||
--danger-gradiend-light: hsl(0,16%,16%);
|
||||
--danger-gradiend-dark: hsl(0,16%,8%);
|
||||
{iconsColour}
|
||||
}}
|
||||
}}")
|
||||
}
|
||||
else
|
||||
{
|
||||
@($@"@media screen and (prefers-color-scheme: light) {{
|
||||
:root {{
|
||||
--colour-index: {PublicCacheData.PageSettings.LightThemeIndexColour};
|
||||
--background: hsl(var(--colour-index,25),84%,88%);
|
||||
--text-color: hsl(var(--colour-index,25),84%,26.4%);
|
||||
--primary-color: hsl(var(--colour-index,25),84%,88%);
|
||||
--primary-color-light: hsl(var(--colour-index,25),84%,100%);
|
||||
--primary-color-dark: hsl(var(--colour-index,25),84%,66%);
|
||||
--primary-gradiend-light: hsl(var(--colour-index,25),84%,92%);
|
||||
--primary-gradiend-dark: hsl(var(--colour-index,25),84%,84%);
|
||||
--primary-gradiend-lighter: hsl(var(--colour-index,25),84%,96%);
|
||||
--primary-gradiend-darker: hsl(var(--colour-index,25),84%,80%);
|
||||
--light-shadow: hsla(var(--colour-index,25),84%,100%, .5);
|
||||
--dark-shadow: hsla(var(--colour-index,25),84%,66%, .5);
|
||||
--danger-gradiend-light: hsl(0,84%,92%);
|
||||
--danger-gradiend-dark: hsl(0,84%,84%);
|
||||
{iconsColour}
|
||||
}}
|
||||
}}
|
||||
|
||||
@media screen and (prefers-color-scheme: dark) {{
|
||||
:root {{
|
||||
--colour-index: {PublicCacheData.PageSettings.DarkThemeIndexColour};
|
||||
--background: hsl(var(--colour-index,215),16%,12%);
|
||||
--text-color: hsl(var(--colour-index,215),16%,73.6%);
|
||||
--primary-color: hsl(var(--colour-index,215),16%,12%);
|
||||
--primary-color-light: hsl(var(--colour-index,215),84%,100%);
|
||||
--primary-color-dark: hsl(var(--colour-index,215),16%,33%);
|
||||
--primary-gradiend-light: hsl(var(--colour-index,215),16%,16%);
|
||||
--primary-gradiend-dark: hsl(var(--colour-index,215),16%,8%);
|
||||
--primary-gradiend-lighter: hsl(var(--colour-index,215),16%,20%);
|
||||
--primary-gradiend-darker: hsl(var(--colour-index,215),16%,4%);
|
||||
--light-shadow: hsla(var(--colour-index,215),84%,66%,.1);
|
||||
--dark-shadow: hsla(var(--colour-index,215),16%,1%,.5);
|
||||
--danger-gradiend-light: hsl(0,16%,16%);
|
||||
--danger-gradiend-dark: hsl(0,16%,8%);
|
||||
{iconsColour}
|
||||
}}
|
||||
}}")
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (PublicCacheData.PageSettings.ThemeIsDarkGray || PublicCacheData.PageSettings.ThemeIsLightGray)
|
||||
{
|
||||
if (PublicCacheData.PageSettings.ThemeIsDarkGray)
|
||||
{
|
||||
@($@":root{{--colour-index: 0;
|
||||
--background: hsl(0,0%,12%);
|
||||
--text-color: hsl(0,0%,73.6%);
|
||||
--primary-color: hsl(0,0%,12%);
|
||||
--primary-color-light: hsl(0,0%,100%);
|
||||
--primary-color-dark: hsl(0,0%,33%);
|
||||
--primary-gradiend-light: hsl(0,0%,16%);
|
||||
--primary-gradiend-dark: hsl(0,0%,8%);
|
||||
--primary-gradiend-lighter: hsl(0,0%,20%);
|
||||
--primary-gradiend-darker: hsl(0,0%,4%);
|
||||
--light-shadow: hsla(0,0%,66%,.1);
|
||||
--dark-shadow: hsla(0,0%,1%,.5);
|
||||
--danger-gradiend-light: hsl(0,16%,16%);
|
||||
--danger-gradiend-dark: hsl(0,16%,8%);{iconsColour}}}")
|
||||
}
|
||||
else
|
||||
{
|
||||
@($@":root{{--colour-index: 0;
|
||||
--background: hsl(0,0%,88%);
|
||||
--text-color: hsl(0,0%,26.4%);
|
||||
--primary-color: hsl(0,0%,88%);
|
||||
--primary-color-light: hsl(0,0%,100%);
|
||||
--primary-color-dark: hsl(0,0%,66%);
|
||||
--primary-gradiend-light: hsl(0,0%,92%);
|
||||
--primary-gradiend-dark: hsl(0,0%,84%);
|
||||
--primary-gradiend-lighter: hsl(0,0%,96%);
|
||||
--primary-gradiend-darker: hsl(0,0%,80%);
|
||||
--light-shadow: hsla(0,0%,100%, .5);
|
||||
--dark-shadow: hsla(0,0%,66%, .5);
|
||||
--danger-gradiend-light: hsl(0,84%,92%);
|
||||
--danger-gradiend-dark: hsl(0,84%,84%);{iconsColour}}}")
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (PublicCacheData.PageSettings.ThemeIsDarkMode)
|
||||
{
|
||||
@($@":root{{--colour-index: {PublicCacheData.PageSettings.DarkThemeIndexColour};
|
||||
--background: hsl(var(--colour-index,215),16%,12%);
|
||||
--text-color: hsl(var(--colour-index,215),16%,73.6%);
|
||||
--primary-color: hsl(var(--colour-index,215),16%,12%);
|
||||
--primary-color-light: hsl(var(--colour-index,215),84%,100%);
|
||||
--primary-color-dark: hsl(var(--colour-index,215),16%,33%);
|
||||
--primary-gradiend-light: hsl(var(--colour-index,215),16%,16%);
|
||||
--primary-gradiend-dark: hsl(var(--colour-index,215),16%,8%);
|
||||
--primary-gradiend-lighter: hsl(var(--colour-index,215),16%,20%);
|
||||
--primary-gradiend-darker: hsl(var(--colour-index,215),16%,4%);
|
||||
--light-shadow: hsla(var(--colour-index,215),84%,66%,.1);
|
||||
--dark-shadow: hsla(var(--colour-index,215),16%,1%,.5);
|
||||
--danger-gradiend-light: hsl(0,16%,16%);
|
||||
--danger-gradiend-dark: hsl(0,16%,8%);{iconsColour}}}")
|
||||
}
|
||||
else
|
||||
{
|
||||
@($@":root{{--colour-index: {PublicCacheData.PageSettings.LightThemeIndexColour};
|
||||
--background: hsl(var(--colour-index,25),84%,88%);
|
||||
--text-color: hsl(var(--colour-index,25),84%,26.4%);
|
||||
--primary-color: hsl(var(--colour-index,25),84%,88%);
|
||||
--primary-color-light: hsl(var(--colour-index,25),84%,100%);
|
||||
--primary-color-dark: hsl(var(--colour-index,25),84%,66%);
|
||||
--primary-gradiend-light: hsl(var(--colour-index,25),84%,92%);
|
||||
--primary-gradiend-dark: hsl(var(--colour-index,25),84%,84%);
|
||||
--primary-gradiend-lighter: hsl(var(--colour-index,25),84%,96%);
|
||||
--primary-gradiend-darker: hsl(var(--colour-index,25),84%,80%);
|
||||
--light-shadow: hsla(var(--colour-index,25),84%,100%, .5);
|
||||
--dark-shadow: hsla(var(--colour-index,25),84%,66%, .5);
|
||||
--danger-gradiend-light: hsl(0,84%,92%);
|
||||
--danger-gradiend-dark: hsl(0,84%,84%);{iconsColour}}}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
</HeadContent>
|
||||
|
||||
<CascadingValue IsFixed=false Value=this>
|
||||
@ChildContent
|
||||
@ -54,7 +197,6 @@
|
||||
|
||||
@code {
|
||||
[Parameter] public RenderFragment ChildContent { get; set; }
|
||||
[Inject] public IStringLocalizer<AllStrings> Localizer { get; set; }
|
||||
[Inject] IStorage DbStorage { get; set; }
|
||||
[Inject] ILocalStorageService Storage { get; set; }
|
||||
[Inject] IJSRuntime JS { get; set; }
|
||||
|
12
LayerComponents/LocalizableComponentBase.cs
Normal file
12
LayerComponents/LocalizableComponentBase.cs
Normal file
@ -0,0 +1,12 @@
|
||||
using collAnon.Client.Services;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace decePubClient.LayerComponents
|
||||
{
|
||||
public class LocalizableComponentBase : ComponentBase
|
||||
{
|
||||
[Inject] public CoalescingStringLocalizer Localizer { get; set; }
|
||||
protected List<Func<Task>> AfterRenderAsyncJobs = new();
|
||||
protected bool IsLoading { get; set; } = true;
|
||||
}
|
||||
}
|
@ -1,9 +1,6 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace decePubClient.LayerComponents
|
||||
namespace decePubClient.LayerComponents
|
||||
{
|
||||
public class PagesBase : ComponentBase
|
||||
public class PagesBase : LocalizableComponentBase
|
||||
{
|
||||
public bool IsLoading { get; set; } = true;
|
||||
}
|
||||
}
|
||||
|
28
Models/PageSettings.cs
Normal file
28
Models/PageSettings.cs
Normal file
@ -0,0 +1,28 @@
|
||||
|
||||
using SocialPub.ClientModels.Resources;
|
||||
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace decePubClient.Models
|
||||
{
|
||||
public class PageSettings
|
||||
{
|
||||
[Required(ErrorMessageResourceName = "Required", ErrorMessageResourceType = typeof(ErrorsResource)),
|
||||
Display(Name = "LanguageId", ResourceType = typeof(FieldsNameResource))]
|
||||
public string CurrentLanguageCode { get; set; } = "en";
|
||||
//public bool NativeNotificationsEnabled { get; set; } = false;
|
||||
[Range(0, 359, ErrorMessageResourceName = nameof(Range), ErrorMessageResourceType = typeof(ErrorsResource))]
|
||||
public short LightThemeIndexColour { get; set; } = 25;
|
||||
[Range(0, 359, ErrorMessageResourceName = nameof(Range), ErrorMessageResourceType = typeof(ErrorsResource))]
|
||||
public short DarkThemeIndexColour { get; set; } = 215;
|
||||
[Range(-2, 359, ErrorMessageResourceName = nameof(Range), ErrorMessageResourceType = typeof(ErrorsResource))]
|
||||
public short IconsThemeIndexColour { get; set; } = 25;
|
||||
|
||||
public bool PreferSystemTheming { get; set; } = true;
|
||||
public bool ThemeIsDarkMode { get; set; } = false;
|
||||
public bool ThemeIsLightGray { get; set; } = true;
|
||||
public bool ThemeIsDarkGray { get; set; } = false;
|
||||
|
||||
public bool ShowDonatorBadge { get; set; } = false;
|
||||
}
|
||||
}
|
@ -1,16 +1,17 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using BlazorZXingJs;
|
||||
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
namespace decePubClient.Models
|
||||
{
|
||||
public class PublicCacheData
|
||||
{
|
||||
public IReadOnlyList<ViewLanguage> Languages { get; set; } = new List<ViewLanguage>();
|
||||
public List<MediaDeviceInfo> QrCodeDevices { get; set; } = new();
|
||||
public string LastPage { get; set; }
|
||||
public string CurrentSubPage { get; set; }
|
||||
public PageSettings PageSettings { get; set; } = new();
|
||||
public bool ShowLogs { get; set; } = false;
|
||||
public IReadOnlyDictionary<string, string> Policies { get; set; } = new ReadOnlyDictionary<string, string>(new Dictionary<string, string>());
|
||||
|
||||
public string CurrentLanguageCode { get; set; } = "en-GB";
|
||||
public bool NativeNotificationsEnabled { get; set; } = false;
|
||||
public short ThemeIndexColour { get; set; } = 25;
|
||||
public bool ThemeIsDarkMode { get; set; } = false;
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
@page "/administration"
|
||||
@inherits PagesBase
|
||||
@inherits LocalizableComponentBase
|
||||
|
||||
<Title>@CascadingState.Localizer["Settings"]</Title>
|
||||
<Title>@Localizer["Settings"]</Title>
|
||||
|
||||
<section class="block relative w-full h-full neomorphInset is-nxsmall rounded-xl">
|
||||
|
||||
@ -10,13 +10,13 @@
|
||||
<OpenDownContainer>
|
||||
<TitleChildren>
|
||||
<p class="inline-flex items-center space-x-2">
|
||||
<i class="ion-md-albums text-xl"></i> <span>@CascadingState.Localizer["Users"]</span>
|
||||
<i class="ion-md-albums text-xl"></i> <span>@Localizer["Users"]</span>
|
||||
</p>
|
||||
</TitleChildren>
|
||||
<InnerContent>
|
||||
<div class="block w-full p-3 md:p-4">
|
||||
<p class="w-full text-center text-lg">
|
||||
<i class="ion-ios-remove-circle-outline"></i> @CascadingState.Localizer["Empty"]
|
||||
<i class="ion-ios-remove-circle-outline"></i> @Localizer["Empty"]
|
||||
</p>
|
||||
</div>
|
||||
</InnerContent>
|
||||
@ -25,13 +25,13 @@
|
||||
<OpenDownContainer>
|
||||
<TitleChildren>
|
||||
<p class="inline-flex items-center space-x-2">
|
||||
<i class="ion-md-albums text-xl"></i> <span>@CascadingState.Localizer["Reports"]</span>
|
||||
<i class="ion-md-albums text-xl"></i> <span>@Localizer["Reports"]</span>
|
||||
</p>
|
||||
</TitleChildren>
|
||||
<InnerContent>
|
||||
<div class="block w-full p-3 md:p-4">
|
||||
<p class="w-full text-center text-lg">
|
||||
<i class="ion-ios-remove-circle-outline"></i> @CascadingState.Localizer["Empty"]
|
||||
<i class="ion-ios-remove-circle-outline"></i> @Localizer["Empty"]
|
||||
</p>
|
||||
</div>
|
||||
</InnerContent>
|
||||
@ -40,13 +40,13 @@
|
||||
<OpenDownContainer>
|
||||
<TitleChildren>
|
||||
<p class="inline-flex items-center space-x-2">
|
||||
<i class="ion-md-albums text-xl"></i> <span>@CascadingState.Localizer["ActivityPub?"]</span>
|
||||
<i class="ion-md-albums text-xl"></i> <span>@Localizer["ActivityPub?"]</span>
|
||||
</p>
|
||||
</TitleChildren>
|
||||
<InnerContent>
|
||||
<div class="block w-full p-3 md:p-4">
|
||||
<p class="w-full text-center text-lg">
|
||||
<i class="ion-ios-remove-circle-outline"></i> @CascadingState.Localizer["Empty"]
|
||||
<i class="ion-ios-remove-circle-outline"></i> @Localizer["Empty"]
|
||||
</p>
|
||||
</div>
|
||||
</InnerContent>
|
||||
@ -55,13 +55,13 @@
|
||||
<OpenDownContainer>
|
||||
<TitleChildren>
|
||||
<p class="inline-flex items-center space-x-2">
|
||||
<i class="ion-md-albums text-xl"></i> <span>@CascadingState.Localizer["Authentication"]</span>
|
||||
<i class="ion-md-albums text-xl"></i> <span>@Localizer["Authentication"]</span>
|
||||
</p>
|
||||
</TitleChildren>
|
||||
<InnerContent>
|
||||
<div class="block w-full p-3 md:p-4">
|
||||
<p class="w-full text-center text-lg">
|
||||
<i class="ion-ios-remove-circle-outline"></i> @CascadingState.Localizer["Empty"]
|
||||
<i class="ion-ios-remove-circle-outline"></i> @Localizer["Empty"]
|
||||
</p>
|
||||
</div>
|
||||
</InnerContent>
|
||||
@ -70,13 +70,13 @@
|
||||
<OpenDownContainer>
|
||||
<TitleChildren>
|
||||
<p class="inline-flex items-center space-x-2">
|
||||
<i class="ion-md-albums text-xl"></i> <span>@CascadingState.Localizer["Emoji?"]</span>
|
||||
<i class="ion-md-albums text-xl"></i> <span>@Localizer["Emoji?"]</span>
|
||||
</p>
|
||||
</TitleChildren>
|
||||
<InnerContent>
|
||||
<div class="block w-full p-3 md:p-4">
|
||||
<p class="w-full text-center text-lg">
|
||||
<i class="ion-ios-remove-circle-outline"></i> @CascadingState.Localizer["Empty"]
|
||||
<i class="ion-ios-remove-circle-outline"></i> @Localizer["Empty"]
|
||||
</p>
|
||||
</div>
|
||||
</InnerContent>
|
||||
@ -85,13 +85,13 @@
|
||||
<OpenDownContainer>
|
||||
<TitleChildren>
|
||||
<p class="inline-flex items-center space-x-2">
|
||||
<i class="ion-md-albums text-xl"></i> <span>@CascadingState.Localizer["Frontend"]</span>
|
||||
<i class="ion-md-albums text-xl"></i> <span>@Localizer["Frontend"]</span>
|
||||
</p>
|
||||
</TitleChildren>
|
||||
<InnerContent>
|
||||
<div class="block w-full p-3 md:p-4">
|
||||
<p class="w-full text-center text-lg">
|
||||
<i class="ion-ios-remove-circle-outline"></i> @CascadingState.Localizer["Empty"]
|
||||
<i class="ion-ios-remove-circle-outline"></i> @Localizer["Empty"]
|
||||
</p>
|
||||
</div>
|
||||
</InnerContent>
|
||||
@ -100,13 +100,13 @@
|
||||
<OpenDownContainer>
|
||||
<TitleChildren>
|
||||
<p class="inline-flex items-center space-x-2">
|
||||
<i class="ion-md-albums text-xl"></i> <span>@CascadingState.Localizer["Instance"]</span>
|
||||
<i class="ion-md-albums text-xl"></i> <span>@Localizer["Instance"]</span>
|
||||
</p>
|
||||
</TitleChildren>
|
||||
<InnerContent>
|
||||
<div class="block w-full p-3 md:p-4">
|
||||
<p class="w-full text-center text-lg">
|
||||
<i class="ion-ios-remove-circle-outline"></i> @CascadingState.Localizer["Empty"]
|
||||
<i class="ion-ios-remove-circle-outline"></i> @Localizer["Empty"]
|
||||
</p>
|
||||
</div>
|
||||
</InnerContent>
|
||||
@ -115,13 +115,13 @@
|
||||
<OpenDownContainer>
|
||||
<TitleChildren>
|
||||
<p class="inline-flex items-center space-x-2">
|
||||
<i class="ion-md-albums text-xl"></i> <span>@CascadingState.Localizer["Link formatter"]</span>
|
||||
<i class="ion-md-albums text-xl"></i> <span>@Localizer["Link formatter"]</span>
|
||||
</p>
|
||||
</TitleChildren>
|
||||
<InnerContent>
|
||||
<div class="block w-full p-3 md:p-4">
|
||||
<p class="w-full text-center text-lg">
|
||||
<i class="ion-ios-remove-circle-outline"></i> @CascadingState.Localizer["Empty"]
|
||||
<i class="ion-ios-remove-circle-outline"></i> @Localizer["Empty"]
|
||||
</p>
|
||||
</div>
|
||||
</InnerContent>
|
||||
@ -130,13 +130,13 @@
|
||||
<OpenDownContainer>
|
||||
<TitleChildren>
|
||||
<p class="inline-flex items-center space-x-2">
|
||||
<i class="ion-md-albums text-xl"></i> <span>@CascadingState.Localizer["Metadata"]</span>
|
||||
<i class="ion-md-albums text-xl"></i> <span>@Localizer["Metadata"]</span>
|
||||
</p>
|
||||
</TitleChildren>
|
||||
<InnerContent>
|
||||
<div class="block w-full p-3 md:p-4">
|
||||
<p class="w-full text-center text-lg">
|
||||
<i class="ion-ios-remove-circle-outline"></i> @CascadingState.Localizer["Empty"]
|
||||
<i class="ion-ios-remove-circle-outline"></i> @Localizer["Empty"]
|
||||
</p>
|
||||
</div>
|
||||
</InnerContent>
|
||||
@ -145,13 +145,13 @@
|
||||
<OpenDownContainer>
|
||||
<TitleChildren>
|
||||
<p class="inline-flex items-center space-x-2">
|
||||
<i class="ion-md-albums text-xl"></i> <span>@CascadingState.Localizer["Policies"]</span>
|
||||
<i class="ion-md-albums text-xl"></i> <span>@Localizer["Policies"]</span>
|
||||
</p>
|
||||
</TitleChildren>
|
||||
<InnerContent>
|
||||
<div class="block w-full p-3 md:p-4">
|
||||
<p class="w-full text-center text-lg">
|
||||
<i class="ion-ios-remove-circle-outline"></i> @CascadingState.Localizer["Empty"]
|
||||
<i class="ion-ios-remove-circle-outline"></i> @Localizer["Empty"]
|
||||
</p>
|
||||
</div>
|
||||
</InnerContent>
|
||||
@ -160,13 +160,13 @@
|
||||
<OpenDownContainer>
|
||||
<TitleChildren>
|
||||
<p class="inline-flex items-center space-x-2">
|
||||
<i class="ion-md-albums text-xl"></i> <span>@CascadingState.Localizer["Upload"]</span>
|
||||
<i class="ion-md-albums text-xl"></i> <span>@Localizer["Upload"]</span>
|
||||
</p>
|
||||
</TitleChildren>
|
||||
<InnerContent>
|
||||
<div class="block w-full p-3 md:p-4">
|
||||
<p class="w-full text-center text-lg">
|
||||
<i class="ion-ios-remove-circle-outline"></i> @CascadingState.Localizer["Empty"]
|
||||
<i class="ion-ios-remove-circle-outline"></i> @Localizer["Empty"]
|
||||
</p>
|
||||
</div>
|
||||
</InnerContent>
|
||||
|
@ -1,7 +1,6 @@
|
||||
@page "/expand"
|
||||
@page "/expand/{messageId}"
|
||||
@inherits PagesBase
|
||||
<Title>@CascadingState.Localizer</Title>
|
||||
@inherits LocalizableComponentBase
|
||||
|
||||
<div class="flex w-full h-full flex-col space-y-4">
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
@page "/"
|
||||
@page "/home"
|
||||
@page "/index"
|
||||
@inherits PagesBase
|
||||
<Title>@CascadingState.Localizer["Index"]</Title>
|
||||
@inherits LocalizableComponentBase
|
||||
<Title>@Localizer["Index"]</Title>
|
||||
|
||||
<div class="flex w-full h-full flex-col space-y-4">
|
||||
|
||||
@ -16,7 +16,7 @@
|
||||
else if (Messages.Count == 0)
|
||||
{
|
||||
<p class="w-full text-center text-lg">
|
||||
<i class="ion-ios-remove-circle-outline"></i> @CascadingState.Localizer["Empty"]
|
||||
<i class="ion-ios-remove-circle-outline"></i> @Localizer["Empty"]
|
||||
</p>
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
@page "/login"
|
||||
@inherits PagesBase
|
||||
<Title>@CascadingState.Localizer["Login"]</Title>
|
||||
@inherits LocalizableComponentBase
|
||||
<Title>@Localizer["Login"]</Title>
|
||||
|
||||
<section class="block relative w-full h-full neomorphInset is-nxsmall rounded-xl">
|
||||
|
||||
|
@ -1,11 +1,11 @@
|
||||
@page "/logout"
|
||||
@inherits PagesBase
|
||||
<Title>@CascadingState.Localizer["Logout"]</Title>
|
||||
@inherits LocalizableComponentBase
|
||||
<Title>@Localizer["Logout"]</Title>
|
||||
|
||||
<section class="block relative w-full h-full neomorphInset is-nxsmall rounded-xl">
|
||||
|
||||
<div class="flex flex-col space-y-4 p-4 md:p-5 w-full h-full absolute overflow-y-auto">
|
||||
<h1 class="text-center">@CascadingState.Localizer["Logging out..."]</h1>
|
||||
<h1 class="text-center">@Localizer["Logging out..."]</h1>
|
||||
</div>
|
||||
|
||||
</section>
|
||||
|
@ -1,6 +1,6 @@
|
||||
@page "/settings"
|
||||
@inherits PagesBase
|
||||
<Title>@CascadingState.Localizer["Settings"]</Title>
|
||||
@inherits LocalizableComponentBase
|
||||
<Title>@Localizer["Settings"]</Title>
|
||||
|
||||
<section class="block relative w-full h-full neomorphInset is-nxsmall rounded-xl">
|
||||
|
||||
@ -9,13 +9,13 @@
|
||||
<OpenDownContainer>
|
||||
<TitleChildren>
|
||||
<p class="inline-flex items-center space-x-2">
|
||||
<i class="ion-md-cog text-xl"></i> <span>@CascadingState.Localizer["General"]</span>
|
||||
<i class="ion-md-cog text-xl"></i> <span>@Localizer["General"]</span>
|
||||
</p>
|
||||
</TitleChildren>
|
||||
<InnerContent>
|
||||
<div class="block w-full p-3 md:p-4">
|
||||
<p class="w-full text-center text-lg">
|
||||
<i class="ion-ios-remove-circle-outline"></i> @CascadingState.Localizer["Empty"]
|
||||
<i class="ion-ios-remove-circle-outline"></i> @Localizer["Empty"]
|
||||
</p>
|
||||
</div>
|
||||
</InnerContent>
|
||||
@ -24,13 +24,13 @@
|
||||
<OpenDownContainer>
|
||||
<TitleChildren>
|
||||
<p class="inline-flex items-center space-x-2">
|
||||
<i class="ion-md-person text-xl"></i> <span>@CascadingState.Localizer["Profile"]</span>
|
||||
<i class="ion-md-person text-xl"></i> <span>@Localizer["Profile"]</span>
|
||||
</p>
|
||||
</TitleChildren>
|
||||
<InnerContent>
|
||||
<div class="block w-full p-3 md:p-4">
|
||||
<p class="w-full text-center text-lg">
|
||||
<i class="ion-ios-remove-circle-outline"></i> @CascadingState.Localizer["Empty"]
|
||||
<i class="ion-ios-remove-circle-outline"></i> @Localizer["Empty"]
|
||||
</p>
|
||||
</div>
|
||||
</InnerContent>
|
||||
@ -39,13 +39,13 @@
|
||||
<OpenDownContainer>
|
||||
<TitleChildren>
|
||||
<p class="inline-flex items-center space-x-2">
|
||||
<i class="ion-md-archive text-xl"></i> <span>@CascadingState.Localizer["Data import/export"]</span>
|
||||
<i class="ion-md-archive text-xl"></i> <span>@Localizer["Data import/export"]</span>
|
||||
</p>
|
||||
</TitleChildren>
|
||||
<InnerContent>
|
||||
<div class="block w-full p-3 md:p-4">
|
||||
<p class="w-full text-center text-lg">
|
||||
<i class="ion-ios-remove-circle-outline"></i> @CascadingState.Localizer["Empty"]
|
||||
<i class="ion-ios-remove-circle-outline"></i> @Localizer["Empty"]
|
||||
</p>
|
||||
</div>
|
||||
</InnerContent>
|
||||
@ -54,13 +54,13 @@
|
||||
<OpenDownContainer>
|
||||
<TitleChildren>
|
||||
<p class="inline-flex items-center space-x-2">
|
||||
<i class="ion-md-eye-off text-xl"></i> <span>@CascadingState.Localizer["Mutes/Blocks"]</span>
|
||||
<i class="ion-md-eye-off text-xl"></i> <span>@Localizer["Mutes/Blocks"]</span>
|
||||
</p>
|
||||
</TitleChildren>
|
||||
<InnerContent>
|
||||
<div class="block w-full p-3 md:p-4">
|
||||
<p class="w-full text-center text-lg">
|
||||
<i class="ion-ios-remove-circle-outline"></i> @CascadingState.Localizer["Empty"]
|
||||
<i class="ion-ios-remove-circle-outline"></i> @Localizer["Empty"]
|
||||
</p>
|
||||
</div>
|
||||
</InnerContent>
|
||||
|
67
Program.cs
67
Program.cs
@ -1,73 +1,62 @@
|
||||
using decePubClient;
|
||||
using Microsoft.AspNetCore.Components.Web;
|
||||
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Text.Json;
|
||||
using Append.Blazor.Notifications;
|
||||
using Blazored.LocalStorage;
|
||||
using Blazored.Modal;
|
||||
using decePubClient.Extensions;
|
||||
using decePubClient.Models;
|
||||
using decePubClient.Services;
|
||||
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
|
||||
using Toolbelt.Blazor.Extensions.DependencyInjection;
|
||||
using Microsoft.AspNetCore.Components.Authorization;
|
||||
using Microsoft.AspNetCore.Components.Web;
|
||||
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Options;
|
||||
using SocialPub.ClientModels;
|
||||
using collAnon.Client.Services;
|
||||
|
||||
var builder = WebAssemblyHostBuilder.CreateDefault(args);
|
||||
builder.RootComponents.Add<App>("#app");
|
||||
// builder.RootComponents.Add<HeadOutlet>("head::after");
|
||||
builder.RootComponents.Add<HeadOutlet>("head::after");
|
||||
|
||||
builder.Services.AddBlazorDownloadFile();
|
||||
builder.Services.AddApiAuthorization();
|
||||
builder.Services.AddOptions()
|
||||
.AddAuthorizationCore(options =>
|
||||
{
|
||||
options.AddPolicy(Policies.IsAdmin, ExtensionMethods.IsAdminPolicy());
|
||||
options.AddPolicy(Policies.IsUser, ExtensionMethods.IsUserPolicy());
|
||||
options.AddPolicy(Policies.IsModerator, ExtensionMethods.IsUserModeratorPolicy());
|
||||
})
|
||||
.AddTransient<AppStatusService>();
|
||||
builder.Services.AddBlazoredLocalStorage(config =>
|
||||
{
|
||||
config.JsonSerializerOptions.WriteIndented = false;
|
||||
config.JsonSerializerOptions.PropertyNameCaseInsensitive = true;
|
||||
config.JsonSerializerOptions.IgnoreReadOnlyProperties = true;
|
||||
config.JsonSerializerOptions.ReadCommentHandling = JsonCommentHandling.Skip;
|
||||
config.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
|
||||
})
|
||||
.AddBlazoredModal()
|
||||
//.AddScoped<TokenAuthStateProvider>()
|
||||
.AddScoped<CustomAuthenticationMessageHandler>()
|
||||
builder.Services.TryAddEnumerable(
|
||||
ServiceDescriptor.Singleton<IPostConfigureOptions<RemoteAuthenticationOptions<ApiAuthorizationProviderOptions>>,
|
||||
ApiAuthorizationOptionsConfiguration>());
|
||||
builder.Services.AddBlazoredLocalStorage(config =>
|
||||
{
|
||||
config.JsonSerializerOptions.WriteIndented = false;
|
||||
config.JsonSerializerOptions.PropertyNameCaseInsensitive = true;
|
||||
config.JsonSerializerOptions.IgnoreReadOnlyProperties = true;
|
||||
config.JsonSerializerOptions.ReadCommentHandling = JsonCommentHandling.Skip;
|
||||
config.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
|
||||
})
|
||||
.AddScoped<TokenAuthStateProvider>()
|
||||
.AddScoped<MessagesService>()
|
||||
//.AddScoped<AuthenticationStateProvider>(provider => provider.GetRequiredService<TokenAuthStateProvider>())
|
||||
.AddScoped<AuthenticationStateProvider>(provider => provider.GetRequiredService<TokenAuthStateProvider>())
|
||||
.AddSingleton(typeof(CoalescingStringLocalizer))
|
||||
//.AddTransient<IHttpService, HttpService>()
|
||||
.AddHeadElementHelper(options => options.DisableClientScriptAutoInjection = true)
|
||||
.AddLocalization()
|
||||
.AddNotifications()
|
||||
.AddTransient<IStorage, Storage>()
|
||||
.AddLogging(lb => lb.SetMinimumLevel(LogLevel.Debug))
|
||||
.AddIndexedDb();
|
||||
|
||||
|
||||
builder.Services.AddOidcAuthentication(options =>
|
||||
{
|
||||
builder.Configuration.Bind("Local", options.ProviderOptions);
|
||||
options.ProviderOptions.Authority = "https://demo.identityserver.io";
|
||||
options.ProviderOptions.ClientId = "interactive.public";
|
||||
options.ProviderOptions.ResponseType = "code";
|
||||
options.ProviderOptions.DefaultScopes.Add("api");
|
||||
options.ProviderOptions.DefaultScopes.Add("email");
|
||||
options.ProviderOptions.DefaultScopes.Add("profile");
|
||||
});
|
||||
|
||||
builder.Services.AddHttpClient("default", client =>
|
||||
{
|
||||
client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress);
|
||||
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
|
||||
});
|
||||
|
||||
builder.Services.AddHttpClient("ComponentsWebAssembly_CSharp.ServerAPI", client =>
|
||||
{
|
||||
client.BaseAddress = new Uri("https://demo.identityserver.io");
|
||||
})
|
||||
//.AddHttpMessageHandler<BaseAddressAuthorizationMessageHandler>()
|
||||
.AddHttpMessageHandler<CustomAuthenticationMessageHandler>();
|
||||
|
||||
builder.Services.AddTransient(sp => sp.GetRequiredService<IHttpClientFactory>().CreateClient("ComponentsWebAssembly_CSharp.ServerAPI"));
|
||||
builder.Services.AddScoped<MessagesService>();
|
||||
builder.Services.AddSingleton(serviceProvider =>
|
||||
{
|
||||
var conf = serviceProvider.GetRequiredService<IConfiguration>();
|
||||
|
7
SCSS/bulma/bulma.sass
vendored
Normal file
7
SCSS/bulma/bulma.sass
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
@charset "utf-8"
|
||||
/*! bulma.io v0.9.4 | MIT License | github.com/jgthms/bulma */
|
||||
@import "sass/utilities/_all"
|
||||
@import "sass/base/_all"
|
||||
@import "sass/elements/_all"
|
||||
@import "sass/form/_all"
|
||||
@import "sass/components/_all"
|
5
SCSS/bulma/sass/base/_all.sass
Normal file
5
SCSS/bulma/sass/base/_all.sass
Normal file
@ -0,0 +1,5 @@
|
||||
/* Bulma Base */
|
||||
@charset "utf-8"
|
||||
|
||||
@import "generic"
|
||||
@import "animations"
|
5
SCSS/bulma/sass/base/animations.sass
Normal file
5
SCSS/bulma/sass/base/animations.sass
Normal file
@ -0,0 +1,5 @@
|
||||
@keyframes spinAround
|
||||
from
|
||||
transform: rotate(0deg)
|
||||
to
|
||||
transform: rotate(359deg)
|
145
SCSS/bulma/sass/base/generic.sass
Normal file
145
SCSS/bulma/sass/base/generic.sass
Normal file
@ -0,0 +1,145 @@
|
||||
@import "../utilities/mixins"
|
||||
|
||||
$body-background-color: $scheme-main !default
|
||||
$body-size: 16px !default
|
||||
$body-min-width: 300px !default
|
||||
$body-rendering: optimizeLegibility !default
|
||||
$body-family: $family-primary !default
|
||||
$body-overflow-x: hidden !default
|
||||
$body-overflow-y: scroll !default
|
||||
|
||||
$body-color: $text !default
|
||||
$body-font-size: 1em !default
|
||||
$body-weight: $weight-normal !default
|
||||
$body-line-height: 1.5 !default
|
||||
|
||||
$code-family: $family-code !default
|
||||
$code-padding: 0.25em 0.5em 0.25em !default
|
||||
$code-weight: normal !default
|
||||
$code-size: 0.875em !default
|
||||
|
||||
$small-font-size: 0.875em !default
|
||||
|
||||
$hr-background-color: $background !default
|
||||
$hr-height: 2px !default
|
||||
$hr-margin: 1.5rem 0 !default
|
||||
|
||||
$strong-color: $text-strong !default
|
||||
$strong-weight: $weight-bold !default
|
||||
|
||||
$pre-font-size: 0.875em !default
|
||||
$pre-padding: 1.25rem 1.5rem !default
|
||||
$pre-code-font-size: 1em !default
|
||||
|
||||
html
|
||||
background-color: $body-background-color
|
||||
font-size: $body-size
|
||||
-moz-osx-font-smoothing: grayscale
|
||||
-webkit-font-smoothing: antialiased
|
||||
min-width: $body-min-width
|
||||
overflow-x: $body-overflow-x
|
||||
overflow-y: $body-overflow-y
|
||||
text-rendering: $body-rendering
|
||||
text-size-adjust: 100%
|
||||
|
||||
article,
|
||||
aside,
|
||||
figure,
|
||||
footer,
|
||||
header,
|
||||
hgroup,
|
||||
section
|
||||
display: block
|
||||
|
||||