This commit is contained in:
Eugene ;) 2022-12-15 20:03:40 +01:00
parent f622fbcf0a
commit 9ef06db411
69 changed files with 5421 additions and 6426 deletions

View File

@ -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>

View File

@ -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>
}

View File

@ -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>

View File

@ -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; }
}

View File

@ -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;
}

View File

@ -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" });
}
}
}

View 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
}
}

View File

@ -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)

View File

@ -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; }

View 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;
}
}

View File

@ -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
View 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;
}
}

View File

@ -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;
}
}

View File

@ -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>

View File

@ -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">

View File

@ -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>
}

View File

@ -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">

View File

@ -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>

View File

@ -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>

View File

@ -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
View 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"

View File

@ -0,0 +1,5 @@
/* Bulma Base */
@charset "utf-8"
@import "generic"
@import "animations"

View File

@ -0,0 +1,5 @@
@keyframes spinAround
from
transform: rotate(0deg)
to
transform: rotate(359deg)

View 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
body,
button,
input,
optgroup,
select,
textarea
font-family: $body-family
code,
pre
-moz-osx-font-smoothing: auto
-webkit-font-smoothing: auto
font-family: $code-family
body
color: $body-color
font-size: $body-font-size
font-weight: $body-weight
line-height: $body-line-height
// Inline
a
color: $link
cursor: pointer
text-decoration: none
strong
color: currentColor
&:hover
color: $link-hover
code
background-color: $code-background
color: $code
font-size: $code-size
font-weight: $code-weight
padding: $code-padding
hr
background-color: $hr-background-color
border: none
display: block
height: $hr-height
margin: $hr-margin
img
height: auto
max-width: 100%
input[type="checkbox"],
input[type="radio"]
vertical-align: baseline
small
font-size: $small-font-size
span
font-style: inherit
font-weight: inherit
strong
color: $strong-color
font-weight: $strong-weight
// Block
fieldset
border: none
pre
+overflow-touch
background-color: $pre-background
color: $pre
font-size: $pre-font-size
overflow-x: auto
padding: $pre-padding
white-space: pre
word-wrap: normal
code
background-color: transparent
color: currentColor
font-size: $pre-code-font-size
padding: 0
table
td,
th
vertical-align: top
&:not([align])
text-align: inherit
th
color: $text-strong

View File

@ -0,0 +1,6 @@
/* Bulma Components */
@charset "utf-8"
@import "dropdown"
@import "message"
@import "pagination"

View File

@ -0,0 +1,83 @@
@import "../utilities/mixins"
$dropdown-menu-min-width: 12rem !default
$dropdown-content-background-color: $scheme-main !default
$dropdown-content-arrow: $link !default
$dropdown-content-offset: 4px !default
$dropdown-content-padding-bottom: 0.5rem !default
$dropdown-content-padding-top: 0.5rem !default
$dropdown-content-radius: $radius !default
$dropdown-content-shadow: $shadow !default
$dropdown-content-z: 20 !default
$dropdown-item-color: $text !default
$dropdown-item-hover-color: $scheme-invert !default
$dropdown-item-hover-background-color: $background !default
$dropdown-item-active-color: $link-invert !default
$dropdown-item-active-background-color: $link !default
$dropdown-divider-background-color: $border-light !default
.dropdown
display: inline-flex
position: relative
vertical-align: top
&.is-active,
&.is-hoverable:hover
.dropdown-menu
display: block
&.is-right
.dropdown-menu
left: auto
right: 0
&.is-up
.dropdown-menu
bottom: 100%
padding-bottom: $dropdown-content-offset
padding-top: initial
top: auto
.dropdown-menu
display: none
+ltr-position(0, false)
min-width: $dropdown-menu-min-width
padding-top: $dropdown-content-offset
position: absolute
top: 100%
z-index: $dropdown-content-z
.dropdown-content
background-color: $dropdown-content-background-color
border-radius: $dropdown-content-radius
box-shadow: $dropdown-content-shadow
padding-bottom: $dropdown-content-padding-bottom
padding-top: $dropdown-content-padding-top
.dropdown-item
color: $dropdown-item-color
display: block
font-size: 0.875rem
line-height: 1.5
padding: 0.375rem 1rem
position: relative
a.dropdown-item,
button.dropdown-item
+ltr-property("padding", 3rem)
text-align: inherit
white-space: nowrap
width: 100%
&:hover
background-color: $dropdown-item-hover-background-color
color: $dropdown-item-hover-color
&.is-active
background-color: $dropdown-item-active-background-color
color: $dropdown-item-active-color
.dropdown-divider
background-color: $dropdown-divider-background-color
border: none
display: block
height: 1px
margin: 0.5rem 0

View File

@ -0,0 +1,101 @@
@import "../utilities/mixins"
$message-background-color: $background !default
$message-radius: $radius !default
$message-header-background-color: $text !default
$message-header-color: $text-invert !default
$message-header-weight: $weight-bold !default
$message-header-padding: 0.75em 1em !default
$message-header-radius: $radius !default
$message-body-border-color: $border !default
$message-body-border-width: 0 0 0 4px !default
$message-body-color: $text !default
$message-body-padding: 1.25em 1.5em !default
$message-body-radius: $radius !default
$message-body-pre-background-color: $scheme-main !default
$message-body-pre-code-background-color: transparent !default
$message-header-body-border-width: 0 !default
$message-colors: $colors !default
.message
@extend %block
background-color: $message-background-color
border-radius: $message-radius
font-size: $size-normal
strong
color: currentColor
a:not(.button):not(.tag):not(.dropdown-item)
color: currentColor
text-decoration: underline
// Sizes
&.is-small
font-size: $size-small
&.is-medium
font-size: $size-medium
&.is-large
font-size: $size-large
// Colors
@each $name, $components in $message-colors
$color: nth($components, 1)
$color-invert: nth($components, 2)
$color-light: null
$color-dark: null
@if length($components) >= 3
$color-light: nth($components, 3)
@if length($components) >= 4
$color-dark: nth($components, 4)
@else
$color-luminance: colorLuminance($color)
$darken-percentage: $color-luminance * 70%
$desaturate-percentage: $color-luminance * 30%
$color-dark: desaturate(darken($color, $darken-percentage), $desaturate-percentage)
@else
$color-lightning: max((100% - lightness($color)) - 2%, 0%)
$color-light: lighten($color, $color-lightning)
&.is-#{$name}
background-color: $color-light
.message-header
background-color: $color
color: $color-invert
.message-body
border-color: $color
color: $color-dark
.message-header
align-items: center
background-color: $message-header-background-color
border-radius: $message-header-radius $message-header-radius 0 0
color: $message-header-color
display: flex
font-weight: $message-header-weight
justify-content: space-between
line-height: 1.25
padding: $message-header-padding
position: relative
.delete
flex-grow: 0
flex-shrink: 0
+ltr-property("margin", 0.75em, false)
& + .message-body
border-width: $message-header-body-border-width
border-top-left-radius: 0
border-top-right-radius: 0
.message-body
border-color: $message-body-border-color
border-radius: $message-body-radius
border-style: solid
border-width: $message-body-border-width
color: $message-body-color
padding: $message-body-padding
code,
pre
background-color: $message-body-pre-background-color
pre code
background-color: $message-body-pre-code-background-color

View File

@ -0,0 +1,167 @@
@import "../utilities/controls"
@import "../utilities/mixins"
$pagination-color: $text-strong !default
$pagination-border-color: $border !default
$pagination-margin: -0.25rem !default
$pagination-min-width: $control-height !default
$pagination-item-font-size: 1em !default
$pagination-item-margin: 0.25rem !default
$pagination-item-padding-left: 0.5em !default
$pagination-item-padding-right: 0.5em !default
$pagination-nav-padding-left: 0.75em !default
$pagination-nav-padding-right: 0.75em !default
$pagination-hover-color: $link-hover !default
$pagination-hover-border-color: $link-hover-border !default
$pagination-focus-color: $link-focus !default
$pagination-focus-border-color: $link-focus-border !default
$pagination-active-color: $link-active !default
$pagination-active-border-color: $link-active-border !default
$pagination-disabled-color: $text-light !default
$pagination-disabled-background-color: $border !default
$pagination-disabled-border-color: $border !default
$pagination-current-color: $link-invert !default
$pagination-current-background-color: $link !default
$pagination-current-border-color: $link !default
$pagination-ellipsis-color: $grey-light !default
$pagination-shadow-inset: inset 0 1px 2px rgba($scheme-invert, 0.2) !default
.pagination
@extend %block
font-size: $size-normal
margin: $pagination-margin
// Sizes
&.is-small
font-size: $size-small
&.is-medium
font-size: $size-medium
&.is-large
font-size: $size-large
&.is-rounded
.pagination-previous,
.pagination-next
padding-left: 1em
padding-right: 1em
border-radius: $radius-rounded
.pagination-link
border-radius: $radius-rounded
.pagination,
.pagination-list
align-items: center
display: flex
justify-content: center
text-align: center
.pagination-previous,
.pagination-next,
.pagination-link,
.pagination-ellipsis
@extend %control
@extend %unselectable
font-size: $pagination-item-font-size
justify-content: center
margin: $pagination-item-margin
padding-left: $pagination-item-padding-left
padding-right: $pagination-item-padding-right
text-align: center
.pagination-previous,
.pagination-next,
.pagination-link
border-color: $pagination-border-color
color: $pagination-color
min-width: $pagination-min-width
&:hover
border-color: $pagination-hover-border-color
color: $pagination-hover-color
&:focus
border-color: $pagination-focus-border-color
&:active
box-shadow: $pagination-shadow-inset
&[disabled],
&.is-disabled
background-color: $pagination-disabled-background-color
border-color: $pagination-disabled-border-color
box-shadow: none
color: $pagination-disabled-color
opacity: 0.5
.pagination-previous,
.pagination-next
padding-left: $pagination-nav-padding-left
padding-right: $pagination-nav-padding-right
white-space: nowrap
.pagination-link
&.is-current
background-color: $pagination-current-background-color
border-color: $pagination-current-border-color
color: $pagination-current-color
.pagination-ellipsis
color: $pagination-ellipsis-color
pointer-events: none
.pagination-list
flex-wrap: wrap
li
list-style: none
+mobile
.pagination
flex-wrap: wrap
.pagination-previous,
.pagination-next
flex-grow: 1
flex-shrink: 1
.pagination-list
li
flex-grow: 1
flex-shrink: 1
+tablet
.pagination-list
flex-grow: 1
flex-shrink: 1
justify-content: flex-start
order: 1
.pagination-previous,
.pagination-next,
.pagination-link,
.pagination-ellipsis
margin-bottom: 0
margin-top: 0
.pagination-previous
order: 2
.pagination-next
order: 3
.pagination
justify-content: space-between
margin-bottom: 0
margin-top: 0
&.is-centered
.pagination-previous
order: 1
.pagination-list
justify-content: center
order: 2
.pagination-next
order: 3
&.is-right
.pagination-previous
order: 1
.pagination-next
order: 2
.pagination-list
justify-content: flex-end
order: 3

View File

@ -0,0 +1,12 @@
/* Bulma Elements */
@charset "utf-8"
@import "button"
@import "content"
@import "icon"
@import "image"
@import "notification"
@import "progress"
@import "tag"
@import "other"

View File

@ -0,0 +1,357 @@
@import "../utilities/controls"
@import "../utilities/mixins"
$button-color: $text-strong !default
$button-background-color: $scheme-main !default
$button-family: false !default
$button-border-color: $border !default
$button-border-width: $control-border-width !default
$button-padding-vertical: calc(0.5em - #{$button-border-width}) !default
$button-padding-horizontal: 1em !default
$button-hover-color: $link-hover !default
$button-hover-border-color: $link-hover-border !default
$button-focus-color: $link-focus !default
$button-focus-border-color: $link-focus-border !default
$button-focus-box-shadow-size: 0 0 0 0.125em !default
$button-focus-box-shadow-color: bulmaRgba($link, 0.25) !default
$button-active-color: $link-active !default
$button-active-border-color: $link-active-border !default
$button-text-color: $text !default
$button-text-decoration: underline !default
$button-text-hover-background-color: $background !default
$button-text-hover-color: $text-strong !default
$button-ghost-background: none !default
$button-ghost-border-color: transparent !default
$button-ghost-color: $link !default
$button-ghost-decoration: none !default
$button-ghost-hover-color: $link !default
$button-ghost-hover-decoration: underline !default
$button-disabled-background-color: $scheme-main !default
$button-disabled-border-color: $border !default
$button-disabled-shadow: none !default
$button-disabled-opacity: 0.5 !default
$button-static-color: $text-light !default
$button-static-background-color: $scheme-main-ter !default
$button-static-border-color: $border !default
$button-colors: $colors !default
$button-responsive-sizes: ("mobile": ("small": ($size-small * 0.75), "normal": ($size-small * 0.875), "medium": $size-small, "large": $size-normal), "tablet-only": ("small": ($size-small * 0.875), "normal": ($size-small), "medium": $size-normal, "large": $size-medium)) !default
// The button sizes use mixins so they can be used at different breakpoints
=button-small
&:not(.is-rounded)
border-radius: $radius-small
font-size: $size-small
=button-normal
font-size: $size-normal
=button-medium
font-size: $size-medium
=button-large
font-size: $size-large
.button
@extend %control
@extend %unselectable
background-color: $button-background-color
border-color: $button-border-color
border-width: $button-border-width
color: $button-color
cursor: pointer
@if $button-family
font-family: $button-family
justify-content: center
padding-bottom: $button-padding-vertical
padding-left: $button-padding-horizontal
padding-right: $button-padding-horizontal
padding-top: $button-padding-vertical
text-align: center
white-space: nowrap
strong
color: inherit
.icon
&,
&.is-small,
&.is-medium,
&.is-large
height: 1.5em
width: 1.5em
&:first-child:not(:last-child)
+ltr-property("margin", calc(#{-0.5 * $button-padding-horizontal} - #{$button-border-width}), false)
+ltr-property("margin", $button-padding-horizontal * 0.25)
&:last-child:not(:first-child)
+ltr-property("margin", $button-padding-horizontal * 0.25, false)
+ltr-property("margin", calc(#{-0.5 * $button-padding-horizontal} - #{$button-border-width}))
&:first-child:last-child
margin-left: calc(#{-0.5 * $button-padding-horizontal} - #{$button-border-width})
margin-right: calc(#{-0.5 * $button-padding-horizontal} - #{$button-border-width})
// States
&:hover,
&.is-hovered
border-color: $button-hover-border-color
color: $button-hover-color
&:focus,
&.is-focused
border-color: $button-focus-border-color
color: $button-focus-color
&:not(:active)
box-shadow: $button-focus-box-shadow-size $button-focus-box-shadow-color
&:active,
&.is-active
border-color: $button-active-border-color
color: $button-active-color
// Colors
&.is-text
background-color: transparent
border-color: transparent
color: $button-text-color
text-decoration: $button-text-decoration
&:hover,
&.is-hovered,
&:focus,
&.is-focused
background-color: $button-text-hover-background-color
color: $button-text-hover-color
&:active,
&.is-active
background-color: bulmaDarken($button-text-hover-background-color, 5%)
color: $button-text-hover-color
&[disabled],
fieldset[disabled] &
background-color: transparent
border-color: transparent
box-shadow: none
&.is-ghost
background: $button-ghost-background
border-color: $button-ghost-border-color
color: $button-ghost-color
text-decoration: $button-ghost-decoration
&:hover,
&.is-hovered
color: $button-ghost-hover-color
text-decoration: $button-ghost-hover-decoration
@each $name, $pair in $button-colors
$color: nth($pair, 1)
$color-invert: nth($pair, 2)
&.is-#{$name}
background-color: $color
border-color: transparent
color: $color-invert
&:hover,
&.is-hovered
background-color: bulmaDarken($color, 2.5%)
border-color: transparent
color: $color-invert
&:focus,
&.is-focused
border-color: transparent
color: $color-invert
&:not(:active)
box-shadow: $button-focus-box-shadow-size bulmaRgba($color, 0.25)
&:active,
&.is-active
background-color: bulmaDarken($color, 5%)
border-color: transparent
color: $color-invert
&[disabled],
fieldset[disabled] &
background-color: $color
border-color: $color
box-shadow: none
&.is-inverted
background-color: $color-invert
color: $color
&:hover,
&.is-hovered
background-color: bulmaDarken($color-invert, 5%)
&[disabled],
fieldset[disabled] &
background-color: $color-invert
border-color: transparent
box-shadow: none
color: $color
&.is-loading
&::after
border-color: transparent transparent $color-invert $color-invert !important
&.is-outlined
background-color: transparent
border-color: $color
color: $color
&:hover,
&.is-hovered,
&:focus,
&.is-focused
background-color: $color
border-color: $color
color: $color-invert
&.is-loading
&::after
border-color: transparent transparent $color $color !important
&:hover,
&.is-hovered,
&:focus,
&.is-focused
&::after
border-color: transparent transparent $color-invert $color-invert !important
&[disabled],
fieldset[disabled] &
background-color: transparent
border-color: $color
box-shadow: none
color: $color
&.is-inverted.is-outlined
background-color: transparent
border-color: $color-invert
color: $color-invert
&:hover,
&.is-hovered,
&:focus,
&.is-focused
background-color: $color-invert
color: $color
&.is-loading
&:hover,
&.is-hovered,
&:focus,
&.is-focused
&::after
border-color: transparent transparent $color $color !important
&[disabled],
fieldset[disabled] &
background-color: transparent
border-color: $color-invert
box-shadow: none
color: $color-invert
// If light and dark colors are provided
@if length($pair) >= 4
$color-light: nth($pair, 3)
$color-dark: nth($pair, 4)
&.is-light
background-color: $color-light
color: $color-dark
&:hover,
&.is-hovered
background-color: bulmaDarken($color-light, 2.5%)
border-color: transparent
color: $color-dark
&:active,
&.is-active
background-color: bulmaDarken($color-light, 5%)
border-color: transparent
color: $color-dark
// Sizes
&.is-small
+button-small
&.is-normal
+button-normal
&.is-medium
+button-medium
&.is-large
+button-large
// Modifiers
&[disabled],
fieldset[disabled] &
background-color: $button-disabled-background-color
border-color: $button-disabled-border-color
box-shadow: $button-disabled-shadow
opacity: $button-disabled-opacity
&.is-fullwidth
display: flex
width: 100%
&.is-loading
color: transparent !important
pointer-events: none
&::after
@extend %loader
+center(1em)
position: absolute !important
&.is-static
background-color: $button-static-background-color
border-color: $button-static-border-color
color: $button-static-color
box-shadow: none
pointer-events: none
&.is-rounded
border-radius: $radius-rounded
padding-left: calc(#{$button-padding-horizontal} + 0.25em)
padding-right: calc(#{$button-padding-horizontal} + 0.25em)
.buttons
align-items: center
display: flex
flex-wrap: wrap
justify-content: flex-start
.button
margin-bottom: 0.5rem
&:not(:last-child):not(.is-fullwidth)
+ltr-property("margin", 0.5rem)
&:last-child
margin-bottom: -0.5rem
&:not(:last-child)
margin-bottom: 1rem
// Sizes
&.are-small
.button:not(.is-normal):not(.is-medium):not(.is-large)
+button-small
&.are-medium
.button:not(.is-small):not(.is-normal):not(.is-large)
+button-medium
&.are-large
.button:not(.is-small):not(.is-normal):not(.is-medium)
+button-large
&.has-addons
.button
&:not(:first-child)
border-bottom-left-radius: 0
border-top-left-radius: 0
&:not(:last-child)
border-bottom-right-radius: 0
border-top-right-radius: 0
+ltr-property("margin", -1px)
&:last-child
+ltr-property("margin", 0)
&:hover,
&.is-hovered
z-index: 2
&:focus,
&.is-focused,
&:active,
&.is-active,
&.is-selected
z-index: 3
&:hover
z-index: 4
&.is-expanded
flex-grow: 1
flex-shrink: 1
&.is-centered
justify-content: center
&:not(.has-addons)
.button:not(.is-fullwidth)
margin-left: 0.25rem
margin-right: 0.25rem
&.is-right
justify-content: flex-end
&:not(.has-addons)
.button:not(.is-fullwidth)
margin-left: 0.25rem
margin-right: 0.25rem
@each $bp-name, $bp-sizes in $button-responsive-sizes
+breakpoint($bp-name)
@each $size, $value in $bp-sizes
@if $size != "normal"
.button.is-responsive.is-#{$size}
font-size: $value
@else
.button.is-responsive,
.button.is-responsive.is-normal
font-size: $value

View File

@ -0,0 +1,162 @@
@import "../utilities/mixins"
$content-heading-color: $text-strong !default
$content-heading-weight: $weight-semibold !default
$content-heading-line-height: 1.125 !default
$content-block-margin-bottom: 1em !default
$content-blockquote-background-color: $background !default
$content-blockquote-border-left: 5px solid $border !default
$content-blockquote-padding: 1.25em 1.5em !default
$content-pre-padding: 1.25em 1.5em !default
$content-table-cell-border: 1px solid $border !default
$content-table-cell-border-width: 0 0 1px !default
$content-table-cell-padding: 0.5em 0.75em !default
$content-table-cell-heading-color: $text-strong !default
$content-table-head-cell-border-width: 0 0 2px !default
$content-table-head-cell-color: $text-strong !default
$content-table-body-last-row-cell-border-bottom-width: 0 !default
$content-table-foot-cell-border-width: 2px 0 0 !default
$content-table-foot-cell-color: $text-strong !default
.content
@extend %block
// Inline
li + li
margin-top: 0.25em
// Block
p,
dl,
ol,
ul,
blockquote,
pre,
table
&:not(:last-child)
margin-bottom: $content-block-margin-bottom
h1,
h2,
h3,
h4,
h5,
h6
color: $content-heading-color
font-weight: $content-heading-weight
line-height: $content-heading-line-height
h1
font-size: 2em
margin-bottom: 0.5em
&:not(:first-child)
margin-top: 1em
h2
font-size: 1.75em
margin-bottom: 0.5714em
&:not(:first-child)
margin-top: 1.1428em
h3
font-size: 1.5em
margin-bottom: 0.6666em
&:not(:first-child)
margin-top: 1.3333em
h4
font-size: 1.25em
margin-bottom: 0.8em
h5
font-size: 1.125em
margin-bottom: 0.8888em
h6
font-size: 1em
margin-bottom: 1em
blockquote
background-color: $content-blockquote-background-color
+ltr-property("border", $content-blockquote-border-left, false)
padding: $content-blockquote-padding
ol
list-style-position: outside
+ltr-property("margin", 2em, false)
margin-top: 1em
&:not([type])
list-style-type: decimal
&.is-lower-alpha
list-style-type: lower-alpha
&.is-lower-roman
list-style-type: lower-roman
&.is-upper-alpha
list-style-type: upper-alpha
&.is-upper-roman
list-style-type: upper-roman
ul
list-style: disc outside
+ltr-property("margin", 2em, false)
margin-top: 1em
ul
list-style-type: circle
margin-top: 0.5em
ul
list-style-type: square
dd
+ltr-property("margin", 2em, false)
figure
margin-left: 2em
margin-right: 2em
text-align: center
&:not(:first-child)
margin-top: 2em
&:not(:last-child)
margin-bottom: 2em
img
display: inline-block
figcaption
font-style: italic
pre
+overflow-touch
overflow-x: auto
padding: $content-pre-padding
white-space: pre
word-wrap: normal
sup,
sub
font-size: 75%
table
width: 100%
td,
th
border: $content-table-cell-border
border-width: $content-table-cell-border-width
padding: $content-table-cell-padding
vertical-align: top
th
color: $content-table-cell-heading-color
&:not([align])
text-align: inherit
thead
td,
th
border-width: $content-table-head-cell-border-width
color: $content-table-head-cell-color
tfoot
td,
th
border-width: $content-table-foot-cell-border-width
color: $content-table-foot-cell-color
tbody
tr
&:last-child
td,
th
border-bottom-width: $content-table-body-last-row-cell-border-bottom-width
.tabs
li + li
margin-top: 0
// Sizes
&.is-small
font-size: $size-small
&.is-normal
font-size: $size-normal
&.is-medium
font-size: $size-medium
&.is-large
font-size: $size-large

View File

@ -0,0 +1,46 @@
$icon-dimensions: 1.5rem !default
$icon-dimensions-small: 1rem !default
$icon-dimensions-medium: 2rem !default
$icon-dimensions-large: 3rem !default
$icon-text-spacing: 0.25em !default
.icon
align-items: center
display: inline-flex
justify-content: center
height: $icon-dimensions
width: $icon-dimensions
// Sizes
&.is-small
height: $icon-dimensions-small
width: $icon-dimensions-small
&.is-medium
height: $icon-dimensions-medium
width: $icon-dimensions-medium
&.is-large
height: $icon-dimensions-large
width: $icon-dimensions-large
.icon-text
align-items: flex-start
color: inherit
display: inline-flex
flex-wrap: wrap
line-height: $icon-dimensions
vertical-align: top
.icon
flex-grow: 0
flex-shrink: 0
&:not(:last-child)
+ltr
margin-right: $icon-text-spacing
+rtl
margin-left: $icon-text-spacing
&:not(:first-child)
+ltr
margin-left: $icon-text-spacing
+rtl
margin-right: $icon-text-spacing
div.icon-text
display: flex

View File

@ -0,0 +1,73 @@
@import "../utilities/mixins"
$dimensions: 16 24 32 48 64 96 128 !default
.image
display: block
position: relative
img
display: block
height: auto
width: 100%
&.is-rounded
border-radius: $radius-rounded
&.is-fullwidth
width: 100%
// Ratio
&.is-square,
&.is-1by1,
&.is-5by4,
&.is-4by3,
&.is-3by2,
&.is-5by3,
&.is-16by9,
&.is-2by1,
&.is-3by1,
&.is-4by5,
&.is-3by4,
&.is-2by3,
&.is-3by5,
&.is-9by16,
&.is-1by2,
&.is-1by3
img,
.has-ratio
@extend %overlay
height: 100%
width: 100%
&.is-square,
&.is-1by1
padding-top: 100%
&.is-5by4
padding-top: 80%
&.is-4by3
padding-top: 75%
&.is-3by2
padding-top: 66.6666%
&.is-5by3
padding-top: 60%
&.is-16by9
padding-top: 56.25%
&.is-2by1
padding-top: 50%
&.is-3by1
padding-top: 33.3333%
&.is-4by5
padding-top: 125%
&.is-3by4
padding-top: 133.3333%
&.is-2by3
padding-top: 150%
&.is-3by5
padding-top: 166.6666%
&.is-9by16
padding-top: 177.7777%
&.is-1by2
padding-top: 200%
&.is-1by3
padding-top: 300%
// Sizes
@each $dimension in $dimensions
&.is-#{$dimension}x#{$dimension}
height: $dimension * 1px
width: $dimension * 1px

View File

@ -0,0 +1,52 @@
@import "../utilities/mixins"
$notification-background-color: $background !default
$notification-code-background-color: $scheme-main !default
$notification-radius: $radius !default
$notification-padding: 1.25rem 2.5rem 1.25rem 1.5rem !default
$notification-padding-ltr: 1.25rem 2.5rem 1.25rem 1.5rem !default
$notification-padding-rtl: 1.25rem 1.5rem 1.25rem 2.5rem !default
$notification-colors: $colors !default
.notification
@extend %block
background-color: $notification-background-color
border-radius: $notification-radius
position: relative
+ltr
padding: $notification-padding-ltr
+rtl
padding: $notification-padding-rtl
a:not(.button):not(.dropdown-item)
color: currentColor
text-decoration: underline
strong
color: currentColor
code,
pre
background: $notification-code-background-color
pre code
background: transparent
& > .delete
+ltr-position(0.5rem)
position: absolute
top: 0.5rem
.title,
.subtitle,
.content
color: currentColor
// Colors
@each $name, $pair in $notification-colors
$color: nth($pair, 1)
$color-invert: nth($pair, 2)
&.is-#{$name}
background-color: $color
color: $color-invert
// If light and dark colors are provided
@if length($pair) >= 4
$color-light: nth($pair, 3)
$color-dark: nth($pair, 4)
&.is-light
background-color: $color-light
color: $color-dark

View File

@ -0,0 +1,28 @@
@import "../utilities/mixins"
.delete
@extend %delete
.heading
display: block
font-size: 11px
letter-spacing: 1px
margin-bottom: 5px
text-transform: uppercase
.loader
@extend %loader
.number
align-items: center
background-color: $background
border-radius: $radius-rounded
display: inline-flex
font-size: $size-medium
height: 2em
justify-content: center
margin-right: 1.5rem
min-width: 2.5em
padding: 0.25rem 0.5rem
text-align: center
vertical-align: top

View File

@ -0,0 +1,73 @@
@import "../utilities/mixins"
$progress-bar-background-color: $border-light !default
$progress-value-background-color: $text !default
$progress-border-radius: $radius-rounded !default
$progress-indeterminate-duration: 1.5s !default
$progress-colors: $colors !default
.progress
@extend %block
-moz-appearance: none
-webkit-appearance: none
border: none
border-radius: $progress-border-radius
display: block
height: $size-normal
overflow: hidden
padding: 0
width: 100%
&::-webkit-progress-bar
background-color: $progress-bar-background-color
&::-webkit-progress-value
background-color: $progress-value-background-color
&::-moz-progress-bar
background-color: $progress-value-background-color
&::-ms-fill
background-color: $progress-value-background-color
border: none
// Colors
@each $name, $pair in $progress-colors
$color: nth($pair, 1)
&.is-#{$name}
&::-webkit-progress-value
background-color: $color
&::-moz-progress-bar
background-color: $color
&::-ms-fill
background-color: $color
&:indeterminate
background-image: linear-gradient(to right, $color 30%, $progress-bar-background-color 30%)
&:indeterminate
animation-duration: $progress-indeterminate-duration
animation-iteration-count: infinite
animation-name: moveIndeterminate
animation-timing-function: linear
background-color: $progress-bar-background-color
background-image: linear-gradient(to right, $text 30%, $progress-bar-background-color 30%)
background-position: top left
background-repeat: no-repeat
background-size: 150% 150%
&::-webkit-progress-bar
background-color: transparent
&::-moz-progress-bar
background-color: transparent
&::-ms-fill
animation-name: none
// Sizes
&.is-small
height: $size-small
&.is-medium
height: $size-medium
&.is-large
height: $size-large
@keyframes moveIndeterminate
from
background-position: 200% 0
to
background-position: -200% 0

View File

@ -0,0 +1,140 @@
@import "../utilities/mixins"
$tag-background-color: $background !default
$tag-color: $text !default
$tag-radius: $radius !default
$tag-delete-margin: 1px !default
$tag-colors: $colors !default
.tags
align-items: center
display: flex
flex-wrap: wrap
justify-content: flex-start
.tag
margin-bottom: 0.5rem
&:not(:last-child)
+ltr-property("margin", 0.5rem)
&:last-child
margin-bottom: -0.5rem
&:not(:last-child)
margin-bottom: 1rem
// Sizes
&.are-medium
.tag:not(.is-normal):not(.is-large)
font-size: $size-normal
&.are-large
.tag:not(.is-normal):not(.is-medium)
font-size: $size-medium
&.is-centered
justify-content: center
.tag
margin-right: 0.25rem
margin-left: 0.25rem
&.is-right
justify-content: flex-end
.tag
&:not(:first-child)
margin-left: 0.5rem
&:not(:last-child)
margin-right: 0
&.has-addons
.tag
+ltr-property("margin", 0)
&:not(:first-child)
+ltr-property("margin", 0, false)
+ltr
border-top-left-radius: 0
border-bottom-left-radius: 0
+rtl
border-top-right-radius: 0
border-bottom-right-radius: 0
&:not(:last-child)
+ltr
border-top-right-radius: 0
border-bottom-right-radius: 0
+rtl
border-top-left-radius: 0
border-bottom-left-radius: 0
.tag:not(body)
align-items: center
background-color: $tag-background-color
border-radius: $tag-radius
color: $tag-color
display: inline-flex
font-size: $size-small
height: 2em
justify-content: center
line-height: 1.5
padding-left: 0.75em
padding-right: 0.75em
white-space: nowrap
.delete
+ltr-property("margin", 0.25rem, false)
+ltr-property("margin", -0.375rem)
// Colors
@each $name, $pair in $tag-colors
$color: nth($pair, 1)
$color-invert: nth($pair, 2)
&.is-#{$name}
background-color: $color
color: $color-invert
// If a light and dark colors are provided
@if length($pair) > 3
$color-light: nth($pair, 3)
$color-dark: nth($pair, 4)
&.is-light
background-color: $color-light
color: $color-dark
// Sizes
&.is-normal
font-size: $size-small
&.is-medium
font-size: $size-normal
&.is-large
font-size: $size-medium
.icon
&:first-child:not(:last-child)
+ltr-property("margin", -0.375em, false)
+ltr-property("margin", 0.1875em)
&:last-child:not(:first-child)
+ltr-property("margin", 0.1875em, false)
+ltr-property("margin", -0.375em)
&:first-child:last-child
+ltr-property("margin", -0.375em, false)
+ltr-property("margin", -0.375em)
// Modifiers
&.is-delete
+ltr-property("margin", $tag-delete-margin, false)
padding: 0
position: relative
width: 2em
&::before,
&::after
background-color: currentColor
content: ""
display: block
left: 50%
position: absolute
top: 50%
transform: translateX(-50%) translateY(-50%) rotate(45deg)
transform-origin: center center
&::before
height: 1px
width: 50%
&::after
height: 50%
width: 1px
&:hover,
&:focus
background-color: darken($tag-background-color, 5%)
&:active
background-color: darken($tag-background-color, 10%)
&.is-rounded
border-radius: $radius-rounded
a.tag
&:hover
text-decoration: underline

View File

@ -0,0 +1,9 @@
/* Bulma Form */
@charset "utf-8"
@import "shared"
@import "input-textarea"
@import "checkbox-radio"
@import "select"
@import "file"
@import "tools"

View File

@ -0,0 +1,22 @@
%checkbox-radio
cursor: pointer
display: inline-block
line-height: 1.25
position: relative
input
cursor: pointer
&:hover
color: $input-hover-color
&[disabled],
fieldset[disabled] &,
input[disabled]
color: $input-disabled-color
cursor: not-allowed
.checkbox
@extend %checkbox-radio
.radio
@extend %checkbox-radio
& + .radio
+ltr-property("margin", 0.5em, false)

View File

@ -0,0 +1,184 @@
$file-border-color: $border !default
$file-radius: $radius !default
$file-cta-background-color: $scheme-main-ter !default
$file-cta-color: $text !default
$file-cta-hover-color: $text-strong !default
$file-cta-active-color: $text-strong !default
$file-name-border-color: $border !default
$file-name-border-style: solid !default
$file-name-border-width: 1px 1px 1px 0 !default
$file-name-max-width: 16em !default
$file-colors: $form-colors !default
.file
@extend %unselectable
align-items: stretch
display: flex
justify-content: flex-start
position: relative
// Colors
@each $name, $pair in $file-colors
$color: nth($pair, 1)
$color-invert: nth($pair, 2)
&.is-#{$name}
.file-cta
background-color: $color
border-color: transparent
color: $color-invert
&:hover,
&.is-hovered
.file-cta
background-color: bulmaDarken($color, 2.5%)
border-color: transparent
color: $color-invert
&:focus,
&.is-focused
.file-cta
border-color: transparent
box-shadow: 0 0 0.5em bulmaRgba($color, 0.25)
color: $color-invert
&:active,
&.is-active
.file-cta
background-color: bulmaDarken($color, 5%)
border-color: transparent
color: $color-invert
// Sizes
&.is-small
font-size: $size-small
&.is-normal
font-size: $size-normal
&.is-medium
font-size: $size-medium
.file-icon
.fa
font-size: 21px
&.is-large
font-size: $size-large
.file-icon
.fa
font-size: 28px
// Modifiers
&.has-name
.file-cta
border-bottom-right-radius: 0
border-top-right-radius: 0
.file-name
border-bottom-left-radius: 0
border-top-left-radius: 0
&.is-empty
.file-cta
border-radius: $file-radius
.file-name
display: none
&.is-boxed
.file-label
flex-direction: column
.file-cta
flex-direction: column
height: auto
padding: 1em 3em
.file-name
border-width: 0 1px 1px
.file-icon
height: 1.5em
width: 1.5em
.fa
font-size: 21px
&.is-small
.file-icon .fa
font-size: 14px
&.is-medium
.file-icon .fa
font-size: 28px
&.is-large
.file-icon .fa
font-size: 35px
&.has-name
.file-cta
border-radius: $file-radius $file-radius 0 0
.file-name
border-radius: 0 0 $file-radius $file-radius
border-width: 0 1px 1px
&.is-centered
justify-content: center
&.is-fullwidth
.file-label
width: 100%
.file-name
flex-grow: 1
max-width: none
&.is-right
justify-content: flex-end
.file-cta
border-radius: 0 $file-radius $file-radius 0
.file-name
border-radius: $file-radius 0 0 $file-radius
border-width: 1px 0 1px 1px
order: -1
.file-label
align-items: stretch
display: flex
cursor: pointer
justify-content: flex-start
overflow: hidden
position: relative
&:hover
.file-cta
background-color: bulmaDarken($file-cta-background-color, 2.5%)
color: $file-cta-hover-color
.file-name
border-color: bulmaDarken($file-name-border-color, 2.5%)
&:active
.file-cta
background-color: bulmaDarken($file-cta-background-color, 5%)
color: $file-cta-active-color
.file-name
border-color: bulmaDarken($file-name-border-color, 5%)
.file-input
height: 100%
left: 0
opacity: 0
outline: none
position: absolute
top: 0
width: 100%
.file-cta,
.file-name
@extend %control
border-color: $file-border-color
border-radius: $file-radius
font-size: 1em
padding-left: 1em
padding-right: 1em
white-space: nowrap
.file-cta
background-color: $file-cta-background-color
color: $file-cta-color
.file-name
border-color: $file-name-border-color
border-style: $file-name-border-style
border-width: $file-name-border-width
display: block
max-width: $file-name-max-width
overflow: hidden
text-align: inherit
text-overflow: ellipsis
.file-icon
align-items: center
display: flex
height: 1em
justify-content: center
+ltr-property("margin", 0.5em)
width: 1em
.fa
font-size: 14px

View File

@ -0,0 +1,66 @@
$textarea-padding: $control-padding-horizontal !default
$textarea-max-height: 40em !default
$textarea-min-height: 8em !default
$textarea-colors: $form-colors !default
%input-textarea
@extend %input
box-shadow: $input-shadow
max-width: 100%
width: 100%
&[readonly]
box-shadow: none
// Colors
@each $name, $pair in $textarea-colors
$color: nth($pair, 1)
&.is-#{$name}
border-color: $color
&:focus,
&.is-focused,
&:active,
&.is-active
box-shadow: $input-focus-box-shadow-size bulmaRgba($color, 0.25)
// Sizes
&.is-small
+control-small
&.is-medium
+control-medium
&.is-large
+control-large
// Modifiers
&.is-fullwidth
display: block
width: 100%
&.is-inline
display: inline
width: auto
.input
@extend %input-textarea
&.is-rounded
border-radius: $radius-rounded
padding-left: calc(#{$control-padding-horizontal} + 0.375em)
padding-right: calc(#{$control-padding-horizontal} + 0.375em)
&.is-static
background-color: transparent
border-color: transparent
box-shadow: none
padding-left: 0
padding-right: 0
.textarea
@extend %input-textarea
display: block
max-width: 100%
min-width: 100%
padding: $textarea-padding
resize: vertical
&:not([rows])
max-height: $textarea-max-height
min-height: $textarea-min-height
&[rows]
height: initial
// Modifiers
&.has-fixed-size
resize: none

View File

@ -0,0 +1,88 @@
$select-colors: $form-colors !default
.select
display: inline-block
max-width: 100%
position: relative
vertical-align: top
&:not(.is-multiple)
height: $input-height
&:not(.is-multiple):not(.is-loading)
&::after
@extend %arrow
border-color: $input-arrow
+ltr-position(1.125em)
z-index: 4
&.is-rounded
select
border-radius: $radius-rounded
+ltr-property("padding", 1em, false)
select
@extend %input
cursor: pointer
display: block
font-size: 1em
max-width: 100%
outline: none
&::-ms-expand
display: none
&[disabled]:hover,
fieldset[disabled] &:hover
border-color: $input-disabled-border-color
&:not([multiple])
+ltr-property("padding", 2.5em)
&[multiple]
height: auto
padding: 0
option
padding: 0.5em 1em
// States
&:not(.is-multiple):not(.is-loading):hover
&::after
border-color: $input-hover-color
// Colors
@each $name, $pair in $select-colors
$color: nth($pair, 1)
&.is-#{$name}
&:not(:hover)::after
border-color: $color
select
border-color: $color
&:hover,
&.is-hovered
border-color: bulmaDarken($color, 5%)
&:focus,
&.is-focused,
&:active,
&.is-active
box-shadow: $input-focus-box-shadow-size bulmaRgba($color, 0.25)
// Sizes
&.is-small
+control-small
&.is-medium
+control-medium
&.is-large
+control-large
// Modifiers
&.is-disabled
&::after
border-color: $input-disabled-color !important
opacity: 0.5
&.is-fullwidth
width: 100%
select
width: 100%
&.is-loading
&::after
@extend %loader
margin-top: 0
position: absolute
+ltr-position(0.625em)
top: 0.625em
transform: none
&.is-small:after
font-size: $size-small
&.is-medium:after
font-size: $size-medium
&.is-large:after
font-size: $size-large

View File

@ -0,0 +1,60 @@
@import "../utilities/controls"
@import "../utilities/mixins"
$form-colors: $colors !default
$input-color: $text-strong !default
$input-background-color: $scheme-main !default
$input-border-color: $border !default
$input-height: $control-height !default
$input-shadow: inset 0 0.0625em 0.125em rgba($scheme-invert, 0.05) !default
$input-placeholder-color: bulmaRgba($input-color, 0.3) !default
$input-hover-color: $text-strong !default
$input-hover-border-color: $border-hover !default
$input-focus-color: $text-strong !default
$input-focus-border-color: $link !default
$input-focus-box-shadow-size: 0 0 0 0.125em !default
$input-focus-box-shadow-color: bulmaRgba($link, 0.25) !default
$input-disabled-color: $text-light !default
$input-disabled-background-color: $background !default
$input-disabled-border-color: $background !default
$input-disabled-placeholder-color: bulmaRgba($input-disabled-color, 0.3) !default
$input-arrow: $link !default
$input-icon-color: $border !default
$input-icon-active-color: $text !default
$input-radius: $radius !default
=input
@extend %control
background-color: $input-background-color
border-color: $input-border-color
border-radius: $input-radius
color: $input-color
+placeholder
color: $input-placeholder-color
&:hover,
&.is-hovered
border-color: $input-hover-border-color
&:focus,
&.is-focused,
&:active,
&.is-active
border-color: $input-focus-border-color
box-shadow: $input-focus-box-shadow-size $input-focus-box-shadow-color
&[disabled],
fieldset[disabled] &
background-color: $input-disabled-background-color
border-color: $input-disabled-border-color
box-shadow: none
color: $input-disabled-color
+placeholder
color: $input-disabled-placeholder-color
%input
+input

View File

@ -0,0 +1,215 @@
$label-color: $text-strong !default
$label-weight: $weight-bold !default
$help-size: $size-small !default
$label-colors: $form-colors !default
.label
color: $label-color
display: block
font-size: $size-normal
font-weight: $label-weight
&:not(:last-child)
margin-bottom: 0.5em
// Sizes
&.is-small
font-size: $size-small
&.is-medium
font-size: $size-medium
&.is-large
font-size: $size-large
.help
display: block
font-size: $help-size
margin-top: 0.25rem
@each $name, $pair in $label-colors
$color: nth($pair, 1)
&.is-#{$name}
color: $color
// Containers
.field
&:not(:last-child)
margin-bottom: 0.75rem
// Modifiers
&.has-addons
display: flex
justify-content: flex-start
.control
&:not(:last-child)
+ltr-property("margin", -1px)
&:not(:first-child):not(:last-child)
.button,
.input,
.select select
border-radius: 0
&:first-child:not(:only-child)
.button,
.input,
.select select
+ltr
border-bottom-right-radius: 0
border-top-right-radius: 0
+rtl
border-bottom-left-radius: 0
border-top-left-radius: 0
&:last-child:not(:only-child)
.button,
.input,
.select select
+ltr
border-bottom-left-radius: 0
border-top-left-radius: 0
+rtl
border-bottom-right-radius: 0
border-top-right-radius: 0
.button,
.input,
.select select
&:not([disabled])
&:hover,
&.is-hovered
z-index: 2
&:focus,
&.is-focused,
&:active,
&.is-active
z-index: 3
&:hover
z-index: 4
&.is-expanded
flex-grow: 1
flex-shrink: 1
&.has-addons-centered
justify-content: center
&.has-addons-right
justify-content: flex-end
&.has-addons-fullwidth
.control
flex-grow: 1
flex-shrink: 0
&.is-grouped
display: flex
justify-content: flex-start
& > .control
flex-shrink: 0
&:not(:last-child)
margin-bottom: 0
+ltr-property("margin", 0.75rem)
&.is-expanded
flex-grow: 1
flex-shrink: 1
&.is-grouped-centered
justify-content: center
&.is-grouped-right
justify-content: flex-end
&.is-grouped-multiline
flex-wrap: wrap
& > .control
&:last-child,
&:not(:last-child)
margin-bottom: 0.75rem
&:last-child
margin-bottom: -0.75rem
&:not(:last-child)
margin-bottom: 0
&.is-horizontal
+tablet
display: flex
.field-label
.label
font-size: inherit
+mobile
margin-bottom: 0.5rem
+tablet
flex-basis: 0
flex-grow: 1
flex-shrink: 0
+ltr-property("margin", 1.5rem)
text-align: right
&.is-small
font-size: $size-small
padding-top: 0.375em
&.is-normal
padding-top: 0.375em
&.is-medium
font-size: $size-medium
padding-top: 0.375em
&.is-large
font-size: $size-large
padding-top: 0.375em
.field-body
.field .field
margin-bottom: 0
+tablet
display: flex
flex-basis: 0
flex-grow: 5
flex-shrink: 1
.field
margin-bottom: 0
& > .field
flex-shrink: 1
&:not(.is-narrow)
flex-grow: 1
&:not(:last-child)
+ltr-property("margin", 0.75rem)
.control
box-sizing: border-box
clear: both
font-size: $size-normal
position: relative
text-align: inherit
// Modifiers
&.has-icons-left,
&.has-icons-right
.input,
.select
&:focus
& ~ .icon
color: $input-icon-active-color
&.is-small ~ .icon
font-size: $size-small
&.is-medium ~ .icon
font-size: $size-medium
&.is-large ~ .icon
font-size: $size-large
.icon
color: $input-icon-color
height: $input-height
pointer-events: none
position: absolute
top: 0
width: $input-height
z-index: 4
&.has-icons-left
.input,
.select select
padding-left: $input-height
.icon.is-left
left: 0
&.has-icons-right
.input,
.select select
padding-right: $input-height
.icon.is-right
right: 0
&.is-loading
&::after
@extend %loader
position: absolute !important
+ltr-position(0.625em)
top: 0.625em
z-index: 4
&.is-small:after
font-size: $size-small
&.is-medium:after
font-size: $size-medium
&.is-large:after
font-size: $size-large

View File

@ -0,0 +1,9 @@
/* Bulma Utilities */
@charset "utf-8"
@import "initial-variables"
@import "functions"
@import "derived-variables"
@import "mixins"
@import "controls"
@import "extends"

View File

@ -0,0 +1,49 @@
@import "derived-variables"
$control-radius: $radius !default
$control-radius-small: $radius-small !default
$control-border-width: 1px !default
$control-height: 2.5em !default
$control-line-height: 1.5 !default
$control-padding-vertical: calc(0.5em - #{$control-border-width}) !default
$control-padding-horizontal: calc(0.75em - #{$control-border-width}) !default
=control
-moz-appearance: none
-webkit-appearance: none
align-items: center
border: $control-border-width solid transparent
border-radius: $control-radius
box-shadow: none
display: inline-flex
font-size: $size-normal
height: $control-height
justify-content: flex-start
line-height: $control-line-height
padding-bottom: $control-padding-vertical
padding-left: $control-padding-horizontal
padding-right: $control-padding-horizontal
padding-top: $control-padding-vertical
position: relative
vertical-align: top
// States
&:focus,
&.is-focused,
&:active,
&.is-active
outline: none
&[disabled],
fieldset[disabled] &
cursor: not-allowed
// The controls sizes use mixins so they can be used at different breakpoints
=control-small
border-radius: $control-radius-small
font-size: $size-small
=control-medium
font-size: $size-medium
=control-large
font-size: $size-large

View File

@ -0,0 +1,114 @@
@import "initial-variables"
@import "functions"
$primary: $turquoise !default
$info: $cyan !default
$success: $green !default
$warning: $yellow !default
$danger: $red !default
$light: $white-ter !default
$dark: $grey-darker !default
// Invert colors
$orange-invert: findColorInvert($orange) !default
$yellow-invert: findColorInvert($yellow) !default
$green-invert: findColorInvert($green) !default
$turquoise-invert: findColorInvert($turquoise) !default
$cyan-invert: findColorInvert($cyan) !default
$blue-invert: findColorInvert($blue) !default
$purple-invert: findColorInvert($purple) !default
$red-invert: findColorInvert($red) !default
$primary-invert: findColorInvert($primary) !default
$primary-light: findLightColor($primary) !default
$primary-dark: findDarkColor($primary) !default
$info-invert: findColorInvert($info) !default
$info-light: findLightColor($info) !default
$info-dark: findDarkColor($info) !default
$success-invert: findColorInvert($success) !default
$success-light: findLightColor($success) !default
$success-dark: findDarkColor($success) !default
$warning-invert: findColorInvert($warning) !default
$warning-light: findLightColor($warning) !default
$warning-dark: findDarkColor($warning) !default
$danger-invert: findColorInvert($danger) !default
$danger-light: findLightColor($danger) !default
$danger-dark: findDarkColor($danger) !default
$light-invert: findColorInvert($light) !default
$dark-invert: findColorInvert($dark) !default
// General colors
$scheme-main: $white !default
$scheme-main-bis: $white-bis !default
$scheme-main-ter: $white-ter !default
$scheme-invert: $black !default
$scheme-invert-bis: $black-bis !default
$scheme-invert-ter: $black-ter !default
$background: $white-ter !default
$border: $grey-lighter !default
$border-hover: $grey-light !default
$border-light: $grey-lightest !default
$border-light-hover: $grey-light !default
// Text colors
$text: $grey-dark !default
$text-invert: findColorInvert($text) !default
$text-light: $grey !default
$text-strong: $grey-darker !default
// Code colors
$code: darken($red, 15%) !default
$code-background: $background !default
$pre: $text !default
$pre-background: $background !default
// Link colors
$link: $blue !default
$link-invert: findColorInvert($link) !default
$link-light: findLightColor($link) !default
$link-dark: findDarkColor($link) !default
$link-visited: $purple !default
$link-hover: $grey-darker !default
$link-hover-border: $grey-light !default
$link-focus: $grey-darker !default
$link-focus-border: $blue !default
$link-active: $grey-darker !default
$link-active-border: $grey-dark !default
// Typography
$family-primary: $family-sans-serif !default
$family-secondary: $family-sans-serif !default
$family-code: $family-monospace !default
$size-small: $size-7 !default
$size-normal: $size-6 !default
$size-medium: $size-5 !default
$size-large: $size-4 !default
// Effects
$shadow: 0 0.5em 1em -0.125em rgba($scheme-invert, 0.1), 0 0px 0 1px rgba($scheme-invert, 0.02) !default
// Lists and maps
$custom-colors: null !default
$custom-shades: null !default
$colors: mergeColorMaps(("white": ($white, $black), "black": ($black, $white), "light": ($light, $light-invert), "dark": ($dark, $dark-invert), "primary": ($primary, $primary-invert, $primary-light, $primary-dark), "link": ($link, $link-invert, $link-light, $link-dark), "info": ($info, $info-invert, $info-light, $info-dark), "success": ($success, $success-invert, $success-light, $success-dark), "warning": ($warning, $warning-invert, $warning-light, $warning-dark), "danger": ($danger, $danger-invert, $danger-light, $danger-dark)), $custom-colors) !default
$shades: mergeColorMaps(("black-bis": $black-bis, "black-ter": $black-ter, "grey-darker": $grey-darker, "grey-dark": $grey-dark, "grey": $grey, "grey-light": $grey-light, "grey-lighter": $grey-lighter, "white-ter": $white-ter, "white-bis": $white-bis), $custom-shades) !default
$sizes: $size-1 $size-2 $size-3 $size-4 $size-5 $size-6 $size-7 !default

View File

@ -0,0 +1,25 @@
@import "mixins"
%control
+control
%unselectable
+unselectable
%arrow
+arrow
%block
+block
%delete
+delete
%loader
+loader
%overlay
+overlay
%reset
+reset

View File

@ -0,0 +1,135 @@
@function mergeColorMaps($bulma-colors, $custom-colors)
// We return at least Bulma's hard-coded colors
$merged-colors: $bulma-colors
// We want a map as input
@if type-of($custom-colors) == 'map'
@each $name, $components in $custom-colors
// The color name should be a string
// and the components either a single color
// or a colors list with at least one element
@if type-of($name) == 'string' and (type-of($components) == 'list' or type-of($components) == 'color') and length($components) >= 1
$color-base: null
$color-invert: null
$color-light: null
$color-dark: null
$value: null
// The param can either be a single color
// or a list of 2 colors
@if type-of($components) == 'color'
$color-base: $components
$color-invert: findColorInvert($color-base)
$color-light: findLightColor($color-base)
$color-dark: findDarkColor($color-base)
@else if type-of($components) == 'list'
$color-base: nth($components, 1)
// If Invert, Light and Dark are provided
@if length($components) > 3
$color-invert: nth($components, 2)
$color-light: nth($components, 3)
$color-dark: nth($components, 4)
// If only Invert and Light are provided
@else if length($components) > 2
$color-invert: nth($components, 2)
$color-light: nth($components, 3)
$color-dark: findDarkColor($color-base)
// If only Invert is provided
@else
$color-invert: nth($components, 2)
$color-light: findLightColor($color-base)
$color-dark: findDarkColor($color-base)
$value: ($color-base, $color-invert, $color-light, $color-dark)
// We only want to merge the map if the color base is an actual color
@if type-of($color-base) == 'color'
// We merge this colors elements as map with Bulma's colors map
// (we can override them this way, no multiple definition for the same name)
// $merged-colors: map_merge($merged-colors, ($name: ($color-base, $color-invert, $color-light, $color-dark)))
$merged-colors: map_merge($merged-colors, ($name: $value))
@return $merged-colors
@function powerNumber($number, $exp)
$value: 1
@if $exp > 0
@for $i from 1 through $exp
$value: $value * $number
@else if $exp < 0
@for $i from 1 through -$exp
$value: divide($value, $number)
@return $value
@function colorLuminance($color)
@if type-of($color) != 'color'
@return 0.55
$color-rgb: ('red': red($color),'green': green($color),'blue': blue($color))
@each $name, $value in $color-rgb
$adjusted: 0
$value: divide($value, 255)
@if $value < 0.03928
$value: divide($value, 12.92)
@else
$value: divide(($value + .055), 1.055)
$value: powerNumber($value, 2)
$color-rgb: map-merge($color-rgb, ($name: $value))
@return (map-get($color-rgb, 'red') * .2126) + (map-get($color-rgb, 'green') * .7152) + (map-get($color-rgb, 'blue') * .0722)
@function findColorInvert($color)
@if (colorLuminance($color) > 0.55)
@return rgba(#000, 0.7)
@else
@return #fff
@function findLightColor($color, $l: 96%)
@if type-of($color) == 'color'
$l: 96%
@if lightness($color) > 96%
$l: lightness($color)
@return change-color($color, $lightness: $l)
@return $background
@function findDarkColor($color, $base-l: 29%)
@if type-of($color) == 'color'
$luminance: colorLuminance($color)
$luminance-delta: (0.53 - $luminance)
$target-l: round($base-l + ($luminance-delta * 53))
@return change-color($color, $lightness: max($base-l, $target-l))
@return $text-strong
@function bulmaRgba($color, $alpha)
@if type-of($color) != 'color'
@return $color
@return rgba($color, $alpha)
@function bulmaDarken($color, $amount)
@if type-of($color) != 'color'
@return $color
@return darken($color, $amount)
@function bulmaLighten($color, $amount)
@if type-of($color) != 'color'
@return $color
@return lighten($color, $amount)
// Custom divide function by @mdo from https://github.com/twbs/bootstrap/pull/34245
// Replaces old slash division deprecated in Dart Sass
@function divide($dividend, $divisor, $precision: 10)
$sign: if($dividend > 0 and $divisor > 0, 1, -1)
$dividend: abs($dividend)
$divisor: abs($divisor)
$quotient: 0
$remainder: $dividend
@if $dividend == 0
@return 0
@if $divisor == 0
@error "Cannot divide by 0"
@if $divisor == 1
@return $dividend
@while $remainder >= $divisor
$quotient: $quotient + 1
$remainder: $remainder - $divisor
@if $remainder > 0 and $precision > 0
$remainder: divide($remainder * 10, $divisor, $precision - 1) * .1
@return ($quotient + $remainder) * $sign

View File

@ -0,0 +1,79 @@
// Colors
$black: hsl(0, 0%, 4%) !default
$black-bis: hsl(0, 0%, 7%) !default
$black-ter: hsl(0, 0%, 14%) !default
$grey-darker: hsl(0, 0%, 21%) !default
$grey-dark: hsl(0, 0%, 29%) !default
$grey: hsl(0, 0%, 48%) !default
$grey-light: hsl(0, 0%, 71%) !default
$grey-lighter: hsl(0, 0%, 86%) !default
$grey-lightest: hsl(0, 0%, 93%) !default
$white-ter: hsl(0, 0%, 96%) !default
$white-bis: hsl(0, 0%, 98%) !default
$white: hsl(0, 0%, 100%) !default
$orange: hsl(14, 100%, 53%) !default
$yellow: hsl(44, 100%, 77%) !default
$green: hsl(153, 53%, 53%) !default
$turquoise: hsl(171, 100%, 41%) !default
$cyan: hsl(207, 61%, 53%) !default
$blue: hsl(229, 53%, 53%) !default
$purple: hsl(271, 100%, 71%) !default
$red: hsl(348, 86%, 61%) !default
// Typography
$family-sans-serif: BlinkMacSystemFont, -apple-system, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", "Helvetica", "Arial", sans-serif !default
$family-monospace: monospace !default
$render-mode: optimizeLegibility !default
$size-1: 3rem !default
$size-2: 2.5rem !default
$size-3: 2rem !default
$size-4: 1.5rem !default
$size-5: 1.25rem !default
$size-6: 1rem !default
$size-7: 0.75rem !default
$weight-light: 300 !default
$weight-normal: 400 !default
$weight-medium: 500 !default
$weight-semibold: 600 !default
$weight-bold: 700 !default
// Spacing
$block-spacing: 1.5rem !default
// Responsiveness
// The container horizontal gap, which acts as the offset for breakpoints
$gap: 32px !default
// 960, 1152, and 1344 have been chosen because they are divisible by both 12 and 16
$tablet: 769px !default
// 960px container + 4rem
$desktop: 960px + (2 * $gap) !default
// 1152px container + 4rem
$widescreen: 1152px + (2 * $gap) !default
$widescreen-enabled: true !default
// 1344px container + 4rem
$fullhd: 1344px + (2 * $gap) !default
$fullhd-enabled: true !default
$breakpoints: ("mobile": ("until": $tablet), "tablet": ("from": $tablet), "tablet-only": ("from": $tablet, "until": $desktop), "touch": ("from": $desktop), "desktop": ("from": $desktop), "desktop-only": ("from": $desktop, "until": $widescreen), "until-widescreen": ("until": $widescreen), "widescreen": ("from": $widescreen), "widescreen-only": ("from": $widescreen, "until": $fullhd), "until-fullhd": ("until": $fullhd), "fullhd": ("from": $fullhd)) !default
// Miscellaneous
$easing: ease-out !default
$radius-small: 2px !default
$radius: 4px !default
$radius-large: 6px !default
$radius-rounded: 9999px !default
$speed: 86ms !default
// Flags
$variable-columns: true !default
$rtl: false !default

View File

@ -0,0 +1,303 @@
@import "derived-variables"
=clearfix
&::after
clear: both
content: " "
display: table
=center($width, $height: 0)
position: absolute
@if $height != 0
left: calc(50% - (#{$width} * 0.5))
top: calc(50% - (#{$height} * 0.5))
@else
left: calc(50% - (#{$width} * 0.5))
top: calc(50% - (#{$width} * 0.5))
=fa($size, $dimensions)
display: inline-block
font-size: $size
height: $dimensions
line-height: $dimensions
text-align: center
vertical-align: top
width: $dimensions
=hamburger($dimensions)
-moz-appearance: none
-webkit-appearance: none
appearance: none
background: none
border: none
cursor: pointer
display: block
height: $dimensions
position: relative
width: $dimensions
span
background-color: currentColor
display: block
height: 1px
left: calc(50% - 8px)
position: absolute
transform-origin: center
transition-duration: $speed
transition-property: background-color, opacity, transform
transition-timing-function: $easing
width: 16px
&:nth-child(1)
top: calc(50% - 6px)
&:nth-child(2)
top: calc(50% - 1px)
&:nth-child(3)
top: calc(50% + 4px)
&:hover
background-color: bulmaRgba(black, 0.05)
// Modifers
&.is-active
span
&:nth-child(1)
transform: translateY(5px) rotate(45deg)
&:nth-child(2)
opacity: 0
&:nth-child(3)
transform: translateY(-5px) rotate(-45deg)
=overflow-touch
-webkit-overflow-scrolling: touch
=placeholder
$placeholders: ':-moz' ':-webkit-input' '-moz' '-ms-input'
@each $placeholder in $placeholders
&:#{$placeholder}-placeholder
@content
=reset
-moz-appearance: none
-webkit-appearance: none
appearance: none
background: none
border: none
color: currentColor
font-family: inherit
font-size: 1em
margin: 0
padding: 0
// Responsiveness
=from($device)
@media screen and (min-width: $device)
@content
=until($device)
@media screen and (max-width: $device - 1px)
@content
=between($from, $until)
@media screen and (min-width: $from) and (max-width: $until - 1px)
@content
=mobile
@media screen and (max-width: $tablet - 1px)
@content
=tablet
@media screen and (min-width: $tablet), print
@content
=tablet-only
@media screen and (min-width: $tablet) and (max-width: $desktop - 1px)
@content
=touch
@media screen and (max-width: $desktop - 1px)
@content
=desktop
@media screen and (min-width: $desktop)
@content
=desktop-only
@if $widescreen-enabled
@media screen and (min-width: $desktop) and (max-width: $widescreen - 1px)
@content
=until-widescreen
@if $widescreen-enabled
@media screen and (max-width: $widescreen - 1px)
@content
=widescreen
@if $widescreen-enabled
@media screen and (min-width: $widescreen)
@content
=widescreen-only
@if $widescreen-enabled and $fullhd-enabled
@media screen and (min-width: $widescreen) and (max-width: $fullhd - 1px)
@content
=until-fullhd
@if $fullhd-enabled
@media screen and (max-width: $fullhd - 1px)
@content
=fullhd
@if $fullhd-enabled
@media screen and (min-width: $fullhd)
@content
=breakpoint($name)
$breakpoint: map-get($breakpoints, $name)
@if $breakpoint
$from: map-get($breakpoint, "from")
$until: map-get($breakpoint, "until")
@if $from and $until
+between($from, $until)
@content
@else if $from
+from($from)
@content
@else if $until
+until($until)
@content
=ltr
@if not $rtl
@content
=rtl
@if $rtl
@content
=ltr-property($property, $spacing, $right: true)
$normal: if($right, "right", "left")
$opposite: if($right, "left", "right")
@if $rtl
#{$property}-#{$opposite}: $spacing
@else
#{$property}-#{$normal}: $spacing
=ltr-position($spacing, $right: true)
$normal: if($right, "right", "left")
$opposite: if($right, "left", "right")
@if $rtl
#{$opposite}: $spacing
@else
#{$normal}: $spacing
// Placeholders
=unselectable
-webkit-touch-callout: none
-webkit-user-select: none
-moz-user-select: none
-ms-user-select: none
user-select: none
=arrow($color: transparent)
border: 3px solid $color
border-radius: 2px
border-right: 0
border-top: 0
content: " "
display: block
height: 0.625em
margin-top: -0.4375em
pointer-events: none
position: absolute
top: 50%
transform: rotate(-45deg)
transform-origin: center
width: 0.625em
=block($spacing: $block-spacing)
&:not(:last-child)
margin-bottom: $spacing
=delete
+unselectable
-moz-appearance: none
-webkit-appearance: none
background-color: bulmaRgba($scheme-invert, 0.2)
border: none
border-radius: $radius-rounded
cursor: pointer
pointer-events: auto
display: inline-block
flex-grow: 0
flex-shrink: 0
font-size: 0
height: 20px
max-height: 20px
max-width: 20px
min-height: 20px
min-width: 20px
outline: none
position: relative
vertical-align: top
width: 20px
&::before,
&::after
background-color: $scheme-main
content: ""
display: block
left: 50%
position: absolute
top: 50%
transform: translateX(-50%) translateY(-50%) rotate(45deg)
transform-origin: center center
&::before
height: 2px
width: 50%
&::after
height: 50%
width: 2px
&:hover,
&:focus
background-color: bulmaRgba($scheme-invert, 0.3)
&:active
background-color: bulmaRgba($scheme-invert, 0.4)
// Sizes
&.is-small
height: 16px
max-height: 16px
max-width: 16px
min-height: 16px
min-width: 16px
width: 16px
&.is-medium
height: 24px
max-height: 24px
max-width: 24px
min-height: 24px
min-width: 24px
width: 24px
&.is-large
height: 32px
max-height: 32px
max-width: 32px
min-height: 32px
min-width: 32px
width: 32px
=loader
animation: spinAround 500ms infinite linear
border: 2px solid $grey-lighter
border-radius: $radius-rounded
border-right-color: transparent
border-top-color: transparent
content: ""
display: block
height: 1em
position: relative
width: 1em
=overlay($offset: 0)
bottom: $offset
left: $offset
position: absolute
right: $offset
top: $offset

View File

@ -6,9 +6,11 @@
.neomorph {
box-shadow: calc(-1 * var(--shadow-offset)) calc(-1 * var(--shadow-offset)) var(--blur-radius) var(--light-shadow), var(--shadow-offset) var(--shadow-offset) var(--blur-radius) var(--dark-shadow);
background-color: var(--background);
&Inset {
box-shadow: inset var(--shadow-offset) var(--shadow-offset) var(--blur-radius) var(--dark-shadow), inset calc(-1 * var(--shadow-offset)) calc(-1 * var(--shadow-offset)) var(--blur-radius) var(--light-shadow);
background-color: var(--background);
&.is-nxxsmall {
--shadow-offset: 2px;
@ -292,7 +294,7 @@
}
}
button.neo,.neo {
button.neo, .neo {
&Btn {
background-image: linear-gradient(145deg, var(--primary-gradiend-light), var(--primary-gradiend-dark));
box-shadow: -3px -3px 6px var(--light-shadow), 3px 3px 6px var(--dark-shadow);
@ -346,6 +348,7 @@ button.neo,.neo {
}
&Plain {
background: var(--background);
box-shadow: -3px -3px 6px var(--light-shadow), 3px 3px 6px var(--dark-shadow);
border: none;

View File

@ -0,0 +1,19 @@
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
using Microsoft.Extensions.Options;
namespace decePubClient.Services
{
public class ApiAuthorizationOptionsConfiguration : IPostConfigureOptions<RemoteAuthenticationOptions<ApiAuthorizationProviderOptions>>
{
public void Configure(RemoteAuthenticationOptions<ApiAuthorizationProviderOptions> options)
{
options.UserOptions.RoleClaim ??= "role";
}
public void PostConfigure(string name, RemoteAuthenticationOptions<ApiAuthorizationProviderOptions> options)
{
if (string.Equals(name, Options.DefaultName))
Configure(options);
}
}
}

View File

@ -0,0 +1,56 @@
using decePubClient.Resources;
using Microsoft.Extensions.Localization;
using SocialPub.ClientModels.Resources;
namespace collAnon.Client.Services
{
public sealed class CoalescingStringLocalizer
{
public readonly IStringLocalizer<AllStrings> _pLocalizer;
readonly IStringLocalizer<FieldsNameResource> _fLocalizer;
readonly IStringLocalizer<ErrorsResource> _eLocalizer;
public CoalescingStringLocalizer(
IStringLocalizer<AllStrings> pLocalizer,
IStringLocalizer<FieldsNameResource> fLocalizer,
IStringLocalizer<ErrorsResource> eLocalizer) =>
(_pLocalizer, _fLocalizer, _eLocalizer) =
(pLocalizer, fLocalizer, eLocalizer);
internal LocalizedString this[string name]
{
get
{
if (_pLocalizer[name].ResourceNotFound)
if (_fLocalizer[name].ResourceNotFound)
if (_eLocalizer[name].ResourceNotFound)
return new(name, name, false);
else
return _eLocalizer[name];
else
return _fLocalizer[name];
else
return _pLocalizer[name];
}
}
internal LocalizedString this[string name, params object[] arguments]
{
get
{
if (_pLocalizer[name].ResourceNotFound)
if (_fLocalizer[name].ResourceNotFound)
if (_eLocalizer[name].ResourceNotFound)
return new(name, name, false);
else
return _eLocalizer[name, arguments];
else
return _fLocalizer[name, arguments];
else
return _pLocalizer[name, arguments];
}
}
}
}

View File

@ -1,18 +1,15 @@
using Blazored.Modal.Services;
using decePubClient.Models;
using decePubClient.Models;
using decePubClient.Models.Types;
namespace decePubClient.Services
{
public class MessagesService
{
readonly IModalService modalService;
readonly IStorage storage;
readonly HttpClient http;
public MessagesService(IHttpClientFactory clientFactory, IModalService modalService, IStorage storage)
public MessagesService(IHttpClientFactory clientFactory, IStorage storage)
{
this.modalService = modalService;
this.storage = storage;
http = clientFactory.CreateClient("default");
}

View File

@ -1,14 +1,15 @@
@inject NavigationManager Navigation
@inherits LocalizableComponentBase
@inject NavigationManager Navigation
<AuthorizeView>
<Authorized>
<button class="button" @onclick="BeginSignOut">
@CascadingState.Localizer["Logout"]
@Localizer["Logout"]
</button>
</Authorized>
<NotAuthorized>
<NavLink ActiveClass="neoBtnSmallInsetPlain" class="button is-rounded neoBtnSmallPlain" href="authentication/login">
@CascadingState.Localizer["Login"]
@Localizer["Login"]
</NavLink>
</NotAuthorized>
</AuthorizeView>

View File

@ -1,4 +1,6 @@
<nav class="flex justify-between align-center pt-3 px-3 md:p-0">
@inherits LocalizableComponentBase
<nav class="flex justify-between align-center pt-3 px-3 md:p-0">
<div class="relative md:w-52">
<button class="button is-rounded inline-flex is-small neoBtnSmall relative md:hidden" @onclick="ToggleNavMenu">
@ -29,47 +31,47 @@
<span class="icon is-left">
<i class="ion-md-home"></i>
</span>
<span>@CascadingState.Localizer["Home"]</span>
<span>@Localizer["Home"]</span>
</NavLink>
<NavLink ActiveClass="neoBtnSmallInsetPlain" class="button has-icons-left is-rounded neoBtnSmallPlain" href="settings">
<span class="icon is-left">
<i class="ion-md-settings"></i>
</span>
<span>@CascadingState.Localizer["Settings"]</span>
<span>@Localizer["Settings"]</span>
</NavLink>
@*<AuthorizeView>
<Authorized>
<NavLink ActiveClass="neoBtnSmallInsetPlain" class="button is-rounded neoBtnSmallPlain" href="administration">
@Localizer["Administration"]
</NavLink>
<NavLink ActiveClass="neoBtnSmallInsetPlain" class="button is-rounded neoBtnSmallPlain" href="logout">
@Localizer["Logout"]
</NavLink>
</Authorized>
<NotAuthorized>
<NavLink ActiveClass="neoBtnSmallInsetPlain" class="button is-rounded neoBtnSmallPlain" href="login">
@Localizer["Login"]
</NavLink>
</NotAuthorized>
</AuthorizeView>*@
<Authorized>
<NavLink ActiveClass="neoBtnSmallInsetPlain" class="button is-rounded neoBtnSmallPlain" href="administration">
@Localizer["Administration"]
</NavLink>
<NavLink ActiveClass="neoBtnSmallInsetPlain" class="button is-rounded neoBtnSmallPlain" href="logout">
@Localizer["Logout"]
</NavLink>
</Authorized>
<NotAuthorized>
<NavLink ActiveClass="neoBtnSmallInsetPlain" class="button is-rounded neoBtnSmallPlain" href="login">
@Localizer["Login"]
</NavLink>
</NotAuthorized>
</AuthorizeView>*@
<NavLink ActiveClass="neoBtnSmallInsetPlain" class="button has-icons-left is-rounded neoBtnSmallPlain" href="administration">
<span class="icon is-left has-text-danger">
<i class="ion-md-switch"></i>
</span>
<span>@CascadingState.Localizer["Administration"]</span>
<span>@Localizer["Administration"]</span>
</NavLink>
<NavLink ActiveClass="neoBtnSmallInsetPlain" class="button has-icons-left is-rounded neoBtnSmallPlain" href="login">
<span class="icon is-left has-text-success">
<i class="ion-md-log-in"></i>
</span>
<span>@CascadingState.Localizer["Login"]</span>
<span>@Localizer["Login"]</span>
</NavLink>
<NavLink ActiveClass="neoBtnSmallInsetPlain" class="button has-icons-left is-rounded neoBtnSmallPlain" href="logout">
<span class="icon is-left has-text-danger">
<i class="ion-md-log-out"></i>
</span>
<span>@CascadingState.Localizer["Logout"]</span>
<span>@Localizer["Logout"]</span>
</NavLink>
<div class="field is-grouped is-align-items-center">
@ -156,8 +158,9 @@
if (!CascadingState.Status.IsMobileMedia())
menuToggle = default;
ThemeIsDarkMode = CascadingState.PublicCacheData?.ThemeIsDarkMode ?? false;
ThemeIndexColour = CascadingState.PublicCacheData?.ThemeIndexColour ?? 25;
ThemeIsDarkMode = CascadingState.PublicCacheData?.PageSettings.ThemeIsDarkMode ?? false;
ThemeIndexColour = ThemeIsDarkMode ? CascadingState.PublicCacheData?.PageSettings.DarkThemeIndexColour ?? 215 :
CascadingState.PublicCacheData?.PageSettings.LightThemeIndexColour ?? 25;
}
private void ToggleNavMenu()
@ -168,7 +171,7 @@
protected async Task ResetToOriginalColour()
{
IsThemeChanging = true;
CascadingState.PublicCacheData.ThemeIndexColour =
CascadingState.PublicCacheData.PageSettings.LightThemeIndexColour =
ThemeIndexColour =
25;
@ -187,7 +190,7 @@
{
IsThemeChanging = true;
var indexColour = short.Parse(eventArgs.Value?.ToString());
CascadingState.PublicCacheData.ThemeIndexColour =
CascadingState.PublicCacheData.PageSettings.LightThemeIndexColour =
ThemeIndexColour =
indexColour;
@ -205,7 +208,7 @@
protected async Task UpdateThemeDarkMode(bool isDarkMode)
{
IsThemeChanging = true;
CascadingState.PublicCacheData.ThemeIsDarkMode =
CascadingState.PublicCacheData.PageSettings.ThemeIsDarkMode =
ThemeIsDarkMode = isDarkMode;
Console.WriteLine("Dark updated {0}", ThemeIsDarkMode);

View File

@ -14,8 +14,6 @@
@using Microsoft.Extensions.Logging
@using Microsoft.JSInterop
@using Toolbelt.Blazor.HeadElement
@using Blazored.Modal
@using Blazored.Modal.Services
@using Blazored.LocalStorage
@using Blazor.DownloadFileFast.Interfaces
@using Markdig

View File

@ -7,15 +7,15 @@
//"wwwroot/vendor/open-iconic.css",
"wwwroot/vendor/ionicons.css",
"wwwroot/vendor/toggle-dark-light-mode.css",
"wwwroot/vendor/bulma.css",
"wwwroot/css/main.css",
"wwwroot/vendor/bulma.min.css",
"wwwroot/css/main.min.css",
"wwwroot/vendor/tailwind.css",
"wwwroot/css/tailwind-override.css"
],
"minify": {
"enabled": false,
"gzip": false,
"brotli": false
"gzip": true,
"brotli": true
},
"sourceMap": false
}

View File

@ -3,7 +3,17 @@
"outputFile": "wwwroot/css/main.css",
"inputFile": "SCSS/main.scss",
"minify": {
"enabled": false
"enabled": true
},
"options": {
"sourceMap": false
}
},
{
"outputFile": "wwwroot/vendor/bulma.css",
"inputFile": "SCSS/bulma/bulma.sass",
"minify": {
"enabled": true
},
"options": {
"sourceMap": false

View File

@ -9,21 +9,19 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="BlazorZXingJs" Version="0.5.13" />
<PackageReference Include="BuildBundlerMinifier" Version="3.2.449" />
<PackageReference Include="BuildWebCompiler" Version="1.12.405" PrivateAssets="all" />
<PackageReference Include="BundlerMinifier.Core" Version="3.2.449" PrivateAssets="all" />
<PackageReference Include="Microsoft.AspNetCore.Components.Authorization" Version="7.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="7.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="7.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="7.0.0" PrivateAssets="all" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="7.0.1" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="7.0.1" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="7.0.1" PrivateAssets="all" />
<PackageReference Include="Microsoft.Extensions.Http" Version="7.0.0" />
<PackageReference Include="Append.Blazor.Notifications" Version="1.1.0" />
<PackageReference Include="BlazorDownloadFileFast" Version="0.2.0" />
<PackageReference Include="Blazored.LocalStorage" Version="4.3.0" />
<PackageReference Include="Blazored.Modal" Version="7.1.0" />
<PackageReference Include="DnetIndexedDb" Version="2.4.1" />
<PackageReference Include="Markdig" Version="0.30.4" />
<PackageReference Include="Microsoft.Extensions.Localization" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Localization" Version="7.0.1" />
<PackageReference Include="Toolbelt.Blazor.HeadElement" Version="7.3.0" />
</ItemGroup>
@ -37,8 +35,6 @@
<AutoGen>True</AutoGen>
<DependentUpon>ErrorMessages.resx</DependentUpon>
</Compile>
<Content Remove="wwwroot\vendor\bulma.css" />
<None Include="wwwroot\vendor\bulma.css" />
<Content Remove="wwwroot\vendor\fontawesome.css" />
<None Include="wwwroot\vendor\fontawesome.css" />
<Content Remove="wwwroot\vendor\ionicons.css" />
@ -85,6 +81,10 @@
<None Include="compilerconfig.json" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\SocialPub\SocialPub\SocialPub.ClientModels\SocialPub.ClientModels.csproj" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Update="Resources\AllStrings.resx">
<Generator>ResXFileCodeGenerator</Generator>

View File

@ -5,6 +5,8 @@ VisualStudioVersion = 17.0.32112.339
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "decePubClient", "decePubClient.csproj", "{EBE69805-3005-49C2-81E4-A314A19F68B6}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SocialPub.ClientModels", "..\SocialPub\SocialPub\SocialPub.ClientModels\SocialPub.ClientModels.csproj", "{5DA9311B-B6BC-4EC6-A26E-10367288F52B}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -15,6 +17,10 @@ Global
{EBE69805-3005-49C2-81E4-A314A19F68B6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EBE69805-3005-49C2-81E4-A314A19F68B6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EBE69805-3005-49C2-81E4-A314A19F68B6}.Release|Any CPU.Build.0 = Release|Any CPU
{5DA9311B-B6BC-4EC6-A26E-10367288F52B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5DA9311B-B6BC-4EC6-A26E-10367288F52B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5DA9311B-B6BC-4EC6-A26E-10367288F52B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5DA9311B-B6BC-4EC6-A26E-10367288F52B}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@ -1,447 +1,572 @@
:root {
--background: #fadcc7;
--text-color: #7c3a0b;
--placeholder-text-color: rgba(124, 58, 11, 0.3);
--black: #0a0a0a;
--black-bis: #121212;
--black-ter: #242424;
--white: #fffefe;
--primary-color: #fadcc7;
--primary-color-light: white;
--primary-color-dark: #f19c5f;
--primary-gradiend-light: #fce8d9;
--primary-gradiend-dark: #f8d0b4;
--primary-gradiend-lighter: #fdf3ec;
--primary-gradiend-darker: #f7c5a1;
--secondary-color: #c7e5fa;
--secondary-color-light: white;
--secondary-color-dark: #b4dcf8;
--light-shadow: rgba(255, 255, 255, 0.5);
--dark-shadow: rgba(241, 156, 95, 0.5);
--background: hsl(25,84%,88%);
--text-color: hsl(25,84%,26.4%);
--placeholder-text-color: hsla(25,84%,26.4%,.3);
--black: hsl(0, 0%, 4%);
--black-bis: hsl(0, 0%, 7%);
--black-ter: hsl(0, 0%, 14%);
--white: hsl(0, 4%, 99.8%);
--primary-color: hsl(25,84%,88%);
--primary-color-light: hsl(25,84%,100%);
--primary-color-dark: hsl(25,84%,66%);
--primary-gradiend-light: hsl(25,84%,92%);
--primary-gradiend-dark: hsl(25,84%,84%);
--primary-gradiend-lighter: hsl(25,84%,96%);
--primary-gradiend-darker: hsl(25,84%,80%);
--secondary-color: hsl(205, 84%, 88%);
--secondary-color-light: hsl(205, 84%, 100%);
--secondary-color-dark: hsl(205, 84%, 84%);
--light-shadow: hsla(25,84%,100%, .5);
--dark-shadow: hsla(25,84%,66%, .5);
/*--fa-primary-color: hsl(25,84%,26.4%);
--fa-secondary-color: hsl(25,84%,66%);*/
--fa-primary-color: #0b4d7c;
--fa-secondary-color: #5fb4f1;
--fa-secondary-color: hsl(25,84%,66%);*/
--fa-primary-color: hsl(205,84%,26.4%);
--fa-secondary-color: hsl(205,84%,66%);
/*--fa-primary-color: hsl(115,84%,26.4%);
--fa-secondary-color: hsl(115,84%,66%);*/
--fa-secondary-color: hsl(115,84%,66%);*/
--fa-primary-opacity: 0.80;
--fa-secondary-opacity: 0.80;
--danger-color: #fbd5d5;
--warning-color: #fbf3d5;
--info-color: #d5f1fb;
--plus-green: #71ba40;
--plus-gold: #cab021; }
--danger-color: hsl(0, 82%, 91%);
--warning-color: hsl(48, 82%, 91%);
--info-color: hsl(196, 82%, 91%);
--plus-green: hsl(96, 49%, 49%);
--plus-gold: hsl(51, 72%, 46%);
}
:root {
--shadow-offset: 8px;
--blur-radius: 16px;
--is-inset: inherit; }
--is-inset: inherit;
}
.neomorph {
box-shadow: calc(-1 * var(--shadow-offset)) calc(-1 * var(--shadow-offset)) var(--blur-radius) var(--light-shadow), var(--shadow-offset) var(--shadow-offset) var(--blur-radius) var(--dark-shadow); }
.neomorphInset {
box-shadow: inset var(--shadow-offset) var(--shadow-offset) var(--blur-radius) var(--dark-shadow), inset calc(-1 * var(--shadow-offset)) calc(-1 * var(--shadow-offset)) var(--blur-radius) var(--light-shadow); }
.neomorphInset.is-nxxsmall {
--shadow-offset: 2px;
--blur-radius: 4px; }
@media (min-width: 640px) {
.neomorphInset.is-nxxsmall-sm {
--shadow-offset: 2px;
--blur-radius: 4px; } }
@media (min-width: 768px) {
.neomorphInset.is-nxxsmall-md {
--shadow-offset: 2px;
--blur-radius: 4px; } }
@media (min-width: 1024px) {
.neomorphInset.is-nxxsmall-lg {
--shadow-offset: 2px;
--blur-radius: 4px; } }
@media (min-width: 1280px) {
.neomorphInset.is-nxxsmall-xl {
--shadow-offset: 2px;
--blur-radius: 4px; } }
.neomorphInset.is-nxsmall {
--shadow-offset: 3px;
--blur-radius: 6px; }
@media (min-width: 640px) {
.neomorphInset.is-nxsmall-sm {
--shadow-offset: 3px;
--blur-radius: 6px; } }
@media (min-width: 768px) {
.neomorphInset.is-nxsmall-md {
--shadow-offset: 3px;
--blur-radius: 6px; } }
@media (min-width: 1024px) {
.neomorphInset.is-nxsmall-lg {
--shadow-offset: 3px;
--blur-radius: 6px; } }
@media (min-width: 1280px) {
.neomorphInset.is-nxsmall-xl {
--shadow-offset: 3px;
--blur-radius: 6px; } }
.neomorphInset.is-nsmall {
--shadow-offset: 6px;
--blur-radius: 12px; }
@media (min-width: 640px) {
.neomorphInset.is-nsmall-sm {
--shadow-offset: 6px;
--blur-radius: 12px; } }
@media (min-width: 768px) {
.neomorphInset.is-nsmall-md {
--shadow-offset: 6px;
--blur-radius: 12px; } }
@media (min-width: 1024px) {
.neomorphInset.is-nsmall-lg {
--shadow-offset: 6px;
--blur-radius: 12px; } }
@media (min-width: 1280px) {
.neomorphInset.is-nsmall-xl {
--shadow-offset: 6px;
--blur-radius: 12px; } }
.neomorph.is-nxxsmall {
box-shadow: calc(-1 * var(--shadow-offset)) calc(-1 * var(--shadow-offset)) var(--blur-radius) var(--light-shadow), var(--shadow-offset) var(--shadow-offset) var(--blur-radius) var(--dark-shadow);
background-color: var(--background);
}
.neomorphInset {
box-shadow: inset var(--shadow-offset) var(--shadow-offset) var(--blur-radius) var(--dark-shadow), inset calc(-1 * var(--shadow-offset)) calc(-1 * var(--shadow-offset)) var(--blur-radius) var(--light-shadow);
background-color: var(--background);
}
.neomorphInset.is-nxxsmall {
--shadow-offset: 2px;
--blur-radius: 4px;
}
@media (min-width: 640px) {
.neomorphInset.is-nxxsmall-sm {
--shadow-offset: 2px;
--blur-radius: 4px; }
@media (min-width: 640px) {
.neomorph.is-nxxsmall-sm {
--shadow-offset: 2px;
--blur-radius: 4px; } }
@media (min-width: 768px) {
.neomorph.is-nxxsmall-md {
--shadow-offset: 2px;
--blur-radius: 4px; } }
@media (min-width: 1024px) {
.neomorph.is-nxxsmall-lg {
--shadow-offset: 2px;
--blur-radius: 4px; } }
@media (min-width: 1280px) {
.neomorph.is-nxxsmall-xl {
--shadow-offset: 2px;
--blur-radius: 4px; } }
.neomorph.is-nxsmall {
--blur-radius: 4px;
}
}
@media (min-width: 768px) {
.neomorphInset.is-nxxsmall-md {
--shadow-offset: 2px;
--blur-radius: 4px;
}
}
@media (min-width: 1024px) {
.neomorphInset.is-nxxsmall-lg {
--shadow-offset: 2px;
--blur-radius: 4px;
}
}
@media (min-width: 1280px) {
.neomorphInset.is-nxxsmall-xl {
--shadow-offset: 2px;
--blur-radius: 4px;
}
}
.neomorphInset.is-nxsmall {
--shadow-offset: 3px;
--blur-radius: 6px;
}
@media (min-width: 640px) {
.neomorphInset.is-nxsmall-sm {
--shadow-offset: 3px;
--blur-radius: 6px; }
@media (min-width: 640px) {
.neomorph.is-nxsmall-sm {
--shadow-offset: 3px;
--blur-radius: 6px; } }
@media (min-width: 768px) {
.neomorph.is-nxsmall-md {
--shadow-offset: 3px;
--blur-radius: 6px; } }
@media (min-width: 1024px) {
.neomorph.is-nxsmall-lg {
--shadow-offset: 3px;
--blur-radius: 6px; } }
@media (min-width: 1280px) {
.neomorph.is-nxsmall-xl {
--shadow-offset: 3px;
--blur-radius: 6px; } }
.neomorph.is-nsmall {
--blur-radius: 6px;
}
}
@media (min-width: 768px) {
.neomorphInset.is-nxsmall-md {
--shadow-offset: 3px;
--blur-radius: 6px;
}
}
@media (min-width: 1024px) {
.neomorphInset.is-nxsmall-lg {
--shadow-offset: 3px;
--blur-radius: 6px;
}
}
@media (min-width: 1280px) {
.neomorphInset.is-nxsmall-xl {
--shadow-offset: 3px;
--blur-radius: 6px;
}
}
.neomorphInset.is-nsmall {
--shadow-offset: 6px;
--blur-radius: 12px;
}
@media (min-width: 640px) {
.neomorphInset.is-nsmall-sm {
--shadow-offset: 6px;
--blur-radius: 12px; }
@media (min-width: 640px) {
.neomorph.is-nsmall-sm {
--shadow-offset: 6px;
--blur-radius: 12px; } }
@media (min-width: 768px) {
.neomorph.is-nsmall-md {
--shadow-offset: 6px;
--blur-radius: 12px; } }
@media (min-width: 1024px) {
.neomorph.is-nsmall-lg {
--shadow-offset: 6px;
--blur-radius: 12px; } }
@media (min-width: 1280px) {
.neomorph.is-nsmall-xl {
--shadow-offset: 6px;
--blur-radius: 12px; } }
.neomorph.is-nnormal {
--blur-radius: 12px;
}
}
@media (min-width: 768px) {
.neomorphInset.is-nsmall-md {
--shadow-offset: 6px;
--blur-radius: 12px;
}
}
@media (min-width: 1024px) {
.neomorphInset.is-nsmall-lg {
--shadow-offset: 6px;
--blur-radius: 12px;
}
}
@media (min-width: 1280px) {
.neomorphInset.is-nsmall-xl {
--shadow-offset: 6px;
--blur-radius: 12px;
}
}
.neomorph.is-nxxsmall {
--shadow-offset: 2px;
--blur-radius: 4px;
}
@media (min-width: 640px) {
.neomorph.is-nxxsmall-sm {
--shadow-offset: 2px;
--blur-radius: 4px;
}
}
@media (min-width: 768px) {
.neomorph.is-nxxsmall-md {
--shadow-offset: 2px;
--blur-radius: 4px;
}
}
@media (min-width: 1024px) {
.neomorph.is-nxxsmall-lg {
--shadow-offset: 2px;
--blur-radius: 4px;
}
}
@media (min-width: 1280px) {
.neomorph.is-nxxsmall-xl {
--shadow-offset: 2px;
--blur-radius: 4px;
}
}
.neomorph.is-nxsmall {
--shadow-offset: 3px;
--blur-radius: 6px;
}
@media (min-width: 640px) {
.neomorph.is-nxsmall-sm {
--shadow-offset: 3px;
--blur-radius: 6px;
}
}
@media (min-width: 768px) {
.neomorph.is-nxsmall-md {
--shadow-offset: 3px;
--blur-radius: 6px;
}
}
@media (min-width: 1024px) {
.neomorph.is-nxsmall-lg {
--shadow-offset: 3px;
--blur-radius: 6px;
}
}
@media (min-width: 1280px) {
.neomorph.is-nxsmall-xl {
--shadow-offset: 3px;
--blur-radius: 6px;
}
}
.neomorph.is-nsmall {
--shadow-offset: 6px;
--blur-radius: 12px;
}
@media (min-width: 640px) {
.neomorph.is-nsmall-sm {
--shadow-offset: 6px;
--blur-radius: 12px;
}
}
@media (min-width: 768px) {
.neomorph.is-nsmall-md {
--shadow-offset: 6px;
--blur-radius: 12px;
}
}
@media (min-width: 1024px) {
.neomorph.is-nsmall-lg {
--shadow-offset: 6px;
--blur-radius: 12px;
}
}
@media (min-width: 1280px) {
.neomorph.is-nsmall-xl {
--shadow-offset: 6px;
--blur-radius: 12px;
}
}
.neomorph.is-nnormal {
--shadow-offset: 8px;
--blur-radius: 16px;
}
@media (min-width: 640px) {
.neomorph.is-nnormal-sm {
--shadow-offset: 8px;
--blur-radius: 16px; }
@media (min-width: 640px) {
.neomorph.is-nnormal-sm {
--shadow-offset: 8px;
--blur-radius: 16px; } }
@media (min-width: 768px) {
.neomorph.is-nnormal-md {
--shadow-offset: 8px;
--blur-radius: 16px; } }
@media (min-width: 1024px) {
.neomorph.is-nnormal-lg {
--shadow-offset: 8px;
--blur-radius: 16px; } }
@media (min-width: 1280px) {
.neomorph.is-nnormal-xl {
--shadow-offset: 8px;
--blur-radius: 16px; } }
--blur-radius: 16px;
}
}
@media (min-width: 768px) {
.neomorph.is-nnormal-md {
--shadow-offset: 8px;
--blur-radius: 16px;
}
}
@media (min-width: 1024px) {
.neomorph.is-nnormal-lg {
--shadow-offset: 8px;
--blur-radius: 16px;
}
}
@media (min-width: 1280px) {
.neomorph.is-nnormal-xl {
--shadow-offset: 8px;
--blur-radius: 16px;
}
}
button.neoBtn, .neoBtn {
background-image: linear-gradient(145deg, var(--primary-gradiend-light), var(--primary-gradiend-dark));
box-shadow: -3px -3px 6px var(--light-shadow), 3px 3px 6px var(--dark-shadow);
border: none;
-webkit-backface-visibility: hidden;
backface-visibility: hidden; }
button.neoBtn:focus, .neoBtn:focus {
background-image: linear-gradient(-45deg, var(--primary-gradiend-light), var(--primary-gradiend-dark));
box-shadow: -3px -3px 6px var(--light-shadow), 3px 3px 6px var(--dark-shadow);
border: none; }
button.neoBtnSmall, .neoBtnSmall {
background-image: linear-gradient(145deg, var(--primary-gradiend-light), var(--primary-gradiend-dark));
box-shadow: -2px -2px 4px var(--light-shadow), 2px 2px 4px var(--dark-shadow);
border: none; }
button.neoBtnSmall:focus, .neoBtnSmall:focus {
background-image: linear-gradient(-45deg, var(--primary-gradiend-light), var(--primary-gradiend-dark));
box-shadow: -2px -2px 4px var(--light-shadow), 2px 2px 4px var(--dark-shadow);
border: none; }
button.neoBtnSmall:focus:not(:active), .neoBtnSmall:focus:not(:active) {
background-image: linear-gradient(-45deg, var(--primary-gradiend-light), var(--primary-gradiend-dark));
box-shadow: -2px -2px 4px var(--light-shadow), 2px 2px 4px var(--dark-shadow); }
button.neoBtnSmall:focus input[type=file], .neoBtnSmall:focus input[type=file] {
background-image: linear-gradient(-45deg, var(--primary-gradiend-light), var(--primary-gradiend-dark)); }
button.neoBtnSmallPlain, .neoBtnSmallPlain {
box-shadow: -3px -3px 6px var(--light-shadow), 3px 3px 6px var(--dark-shadow);
border: none; }
button.neoBtnSmallPlain:focus, .neoBtnSmallPlain:focus {
box-shadow: -3px -3px 6px var(--light-shadow), 3px 3px 6px var(--dark-shadow);
border: none; }
button.neoBtnSmallInsetPlain, .neoBtnSmallInsetPlain {
background-image: linear-gradient(145deg, var(--primary-gradiend-dark), var(--primary-gradiend-light));
box-shadow: inset 3px 3px 6px var(--dark-shadow), inset -3px -3px 6px var(--light-shadow);
border: none; }
button.neoBtnSmallInsetPlain:focus, .neoBtnSmallInsetPlain:focus {
background-image: linear-gradient(145deg, var(--primary-gradiend-darker), var(--primary-gradiend-lighter));
box-shadow: inset 3px 3px 6px var(--dark-shadow), inset -3px -3px 6px var(--light-shadow);
border: none; }
button.neoBtnSmallXInsetPlain, .neoBtnSmallXInsetPlain {
background-image: linear-gradient(145deg, var(--primary-gradiend-dark), var(--primary-gradiend-light));
box-shadow: inset 2px 2px 4px var(--dark-shadow), inset -2px -2px 4px var(--light-shadow);
border: none; }
button.neoBtnSmallXInsetPlain:focus, .neoBtnSmallXInsetPlain:focus {
background-image: linear-gradient(145deg, var(--primary-gradiend-darker), var(--primary-gradiend-lighter));
box-shadow: inset 2px 2px 4px var(--dark-shadow), inset -2px -2px 4px var(--light-shadow);
border: none; }
button.neoBtnInsetPlain, .neoBtnInsetPlain {
background-image: linear-gradient(145deg, var(--primary-gradiend-dark), var(--primary-gradiend-light));
box-shadow: inset 3px 3px 6px var(--dark-shadow), inset -3px -3px 6px var(--light-shadow);
border: none; }
button.neoBtnInsetPlain:focus, .neoBtnInsetPlain:focus {
background-image: linear-gradient(145deg, var(--primary-gradiend-darker), var(--primary-gradiend-lighter));
box-shadow: inset 3px 3px 6px var(--dark-shadow), inset -3px -3px 6px var(--light-shadow);
border: none; }
button.neoBtnInsetPlain:focus:not(:active), .neoBtnInsetPlain:focus:not(:active) {
background-image: linear-gradient(145deg, var(--primary-gradiend-darker), var(--primary-gradiend-lighter));
box-shadow: inset 3px 3px 6px var(--dark-shadow), inset -3px -3px 6px var(--light-shadow); }
backface-visibility: hidden;
}
button.neoBtn:focus, .neoBtn:focus {
background-image: linear-gradient(-45deg, var(--primary-gradiend-light), var(--primary-gradiend-dark));
box-shadow: -3px -3px 6px var(--light-shadow), 3px 3px 6px var(--dark-shadow);
border: none;
}
button.neoBtnSmall, .neoBtnSmall {
background-image: linear-gradient(145deg, var(--primary-gradiend-light), var(--primary-gradiend-dark));
box-shadow: -2px -2px 4px var(--light-shadow), 2px 2px 4px var(--dark-shadow);
border: none;
}
button.neoBtnSmall:focus, .neoBtnSmall:focus {
background-image: linear-gradient(-45deg, var(--primary-gradiend-light), var(--primary-gradiend-dark));
box-shadow: -2px -2px 4px var(--light-shadow), 2px 2px 4px var(--dark-shadow);
border: none;
}
button.neoBtnSmall:focus:not(:active), .neoBtnSmall:focus:not(:active) {
background-image: linear-gradient(-45deg, var(--primary-gradiend-light), var(--primary-gradiend-dark));
box-shadow: -2px -2px 4px var(--light-shadow), 2px 2px 4px var(--dark-shadow);
}
button.neoBtnSmall:focus input[type=file], .neoBtnSmall:focus input[type=file] {
background-image: linear-gradient(-45deg, var(--primary-gradiend-light), var(--primary-gradiend-dark));
}
button.neoBtnSmallPlain, .neoBtnSmallPlain {
background: var(--background);
box-shadow: -3px -3px 6px var(--light-shadow), 3px 3px 6px var(--dark-shadow);
border: none;
}
button.neoBtnSmallPlain:focus, .neoBtnSmallPlain:focus {
box-shadow: -3px -3px 6px var(--light-shadow), 3px 3px 6px var(--dark-shadow);
border: none;
}
button.neoBtnSmallInsetPlain, .neoBtnSmallInsetPlain {
background-image: linear-gradient(145deg, var(--primary-gradiend-dark), var(--primary-gradiend-light));
box-shadow: inset 3px 3px 6px var(--dark-shadow), inset -3px -3px 6px var(--light-shadow);
border: none;
}
button.neoBtnSmallInsetPlain:focus, .neoBtnSmallInsetPlain:focus {
background-image: linear-gradient(145deg, var(--primary-gradiend-darker), var(--primary-gradiend-lighter));
box-shadow: inset 3px 3px 6px var(--dark-shadow), inset -3px -3px 6px var(--light-shadow);
border: none;
}
button.neoBtnSmallXInsetPlain, .neoBtnSmallXInsetPlain {
background-image: linear-gradient(145deg, var(--primary-gradiend-dark), var(--primary-gradiend-light));
box-shadow: inset 2px 2px 4px var(--dark-shadow), inset -2px -2px 4px var(--light-shadow);
border: none;
}
button.neoBtnSmallXInsetPlain:focus, .neoBtnSmallXInsetPlain:focus {
background-image: linear-gradient(145deg, var(--primary-gradiend-darker), var(--primary-gradiend-lighter));
box-shadow: inset 2px 2px 4px var(--dark-shadow), inset -2px -2px 4px var(--light-shadow);
border: none;
}
button.neoBtnInsetPlain, .neoBtnInsetPlain {
background-image: linear-gradient(145deg, var(--primary-gradiend-dark), var(--primary-gradiend-light));
box-shadow: inset 3px 3px 6px var(--dark-shadow), inset -3px -3px 6px var(--light-shadow);
border: none;
}
button.neoBtnInsetPlain:focus, .neoBtnInsetPlain:focus {
background-image: linear-gradient(145deg, var(--primary-gradiend-darker), var(--primary-gradiend-lighter));
box-shadow: inset 3px 3px 6px var(--dark-shadow), inset -3px -3px 6px var(--light-shadow);
border: none;
}
button.neoBtnInsetPlain:focus:not(:active), .neoBtnInsetPlain:focus:not(:active) {
background-image: linear-gradient(145deg, var(--primary-gradiend-darker), var(--primary-gradiend-lighter));
box-shadow: inset 3px 3px 6px var(--dark-shadow), inset -3px -3px 6px var(--light-shadow);
}
button.neoFile, .neoFile {
box-shadow: 0px 0px 0px var(--light-shadow), 0px 0px 0px var(--dark-shadow);
transition: all .2s linear;
transition: all 0.2s linear;
-webkit-backface-visibility: hidden;
backface-visibility: hidden; }
button.neoFile:hover, .neoFile:hover {
box-shadow: -3px -3px 6px var(--light-shadow), 3px 3px 6px var(--dark-shadow); }
button.neoFile:focus-visible, .neoFile:focus-visible {
background: linear-gradient(-45deg, var(--primary-gradiend-light), var(--primary-gradiend-dark));
box-shadow: inset 3px 3px 6px var(--dark-shadow), inset -3px -3px 6px var(--light-shadow);
outline: none; }
button.neoFile.isSelected, .neoFile.isSelected {
background: linear-gradient(145deg, var(--primary-gradiend-dark), var(--primary-gradiend-light));
box-shadow: inset 3px 3px 6px var(--dark-shadow), inset -3px -3px 6px var(--light-shadow); }
button.neoFile.isSelected:focus-visible, .neoFile.isSelected:focus-visible {
background: linear-gradient(-45deg, var(--primary-gradiend-lighter), var(--primary-gradiend-darker));
outline: none; }
button.neoFile.is-active, button.neoFile.active, .neoFile.is-active, .neoFile.active {
box-shadow: inset 3px 3px 6px var(--dark-shadow), inset -3px -3px 6px var(--light-shadow);
color: var(--black); }
backface-visibility: hidden;
}
button.neoFile:hover, .neoFile:hover {
box-shadow: -3px -3px 6px var(--light-shadow), 3px 3px 6px var(--dark-shadow);
}
button.neoFile:focus-visible, .neoFile:focus-visible {
background: linear-gradient(-45deg, var(--primary-gradiend-light), var(--primary-gradiend-dark));
box-shadow: inset 3px 3px 6px var(--dark-shadow), inset -3px -3px 6px var(--light-shadow);
outline: none;
}
button.neoFile.isSelected, .neoFile.isSelected {
background: linear-gradient(145deg, var(--primary-gradiend-dark), var(--primary-gradiend-light));
box-shadow: inset 3px 3px 6px var(--dark-shadow), inset -3px -3px 6px var(--light-shadow);
}
button.neoFile.isSelected:focus-visible, .neoFile.isSelected:focus-visible {
background: linear-gradient(-45deg, var(--primary-gradiend-lighter), var(--primary-gradiend-darker));
outline: none;
}
button.neoFile.is-active, button.neoFile.active, .neoFile.is-active, .neoFile.active {
box-shadow: inset 3px 3px 6px var(--dark-shadow), inset -3px -3px 6px var(--light-shadow);
color: var(--black);
}
button.neoInput, .neoInput {
box-shadow: inset 2px 2px 4px var(--dark-shadow), inset -2px -2px 4px var(--light-shadow);
background: linear-gradient(145deg, var(--primary-gradiend-dark), var(--primary-gradiend-light));
border: none; }
button.neoInput:focus, .neoInput:focus {
background: linear-gradient(145deg, var(--primary-gradiend-darker), var(--primary-gradiend-lighter));
border: none; }
border: none;
}
button.neoInput:focus, .neoInput:focus {
background: linear-gradient(145deg, var(--primary-gradiend-darker), var(--primary-gradiend-lighter));
border: none;
}
button.neoSelect > select, .neoSelect > select {
box-shadow: inset 2px 2px 4px var(--dark-shadow), inset -2px -2px 4px var(--light-shadow);
background: linear-gradient(145deg, var(--primary-gradiend-dark), var(--primary-gradiend-light));
border: none; }
button.neoSelect > select:focus, .neoSelect > select:focus {
background: linear-gradient(145deg, var(--primary-gradiend-darker), var(--primary-gradiend-lighter));
border: none; }
border: none;
}
button.neoSelect > select:focus, .neoSelect > select:focus {
background: linear-gradient(145deg, var(--primary-gradiend-darker), var(--primary-gradiend-lighter));
border: none;
}
.neoCheckbox {
opacity: 0;
width: 0; }
.neoCheckbox:focus + label:before {
background: linear-gradient(145deg, var(--primary-gradiend-darker), var(--primary-gradiend-lighter)) !important; }
.neoCheckboxContainer {
position: relative; }
.neoCheckbox + label {
padding: .15rem .15rem .15rem 2rem;
cursor: pointer;
font-size: 1rem;
line-height: 1.5; }
.neoCheckbox + label:before {
animation-name: none;
width: 1.5rem;
height: 1.5rem;
border-radius: 100px;
position: absolute;
left: 0;
top: 0rem;
content: '';
border: none;
box-shadow: inset 2px 2px 4px var(--dark-shadow), inset -2px -2px 4px var(--light-shadow);
background: linear-gradient(145deg, var(--primary-gradiend-dark), var(--primary-gradiend-light)) !important; }
.neoCheckbox:checked.is-checked-bold + label {
font-weight: bold; }
.neoCheckbox:checked + label:after {
display: inline-block;
width: .375rem;
height: .6rem;
top: .35rem;
left: .55rem;
transform: translateY(0rem) rotate(45deg);
border-width: .1rem;
border-top-width: 0.1rem;
border-left-width: 0.1rem;
border-style: solid;
border-top-style: solid;
border-left-style: solid;
border-color: var(--text-color);
border-top: 0;
border-left: 0;
position: absolute;
content: ''; }
width: 0;
}
.neoCheckbox:focus + label:before {
background: linear-gradient(145deg, var(--primary-gradiend-darker), var(--primary-gradiend-lighter)) !important;
}
.neoCheckboxContainer {
position: relative;
}
.neoCheckbox + label {
padding: 0.15rem 0.15rem 0.15rem 2rem;
cursor: pointer;
font-size: 1rem;
line-height: 1.5;
}
.neoCheckbox + label:before {
animation-name: none;
width: 1.5rem;
height: 1.5rem;
border-radius: 100px;
position: absolute;
left: 0;
top: 0rem;
content: "";
border: none;
box-shadow: inset 2px 2px 4px var(--dark-shadow), inset -2px -2px 4px var(--light-shadow);
background: linear-gradient(145deg, var(--primary-gradiend-dark), var(--primary-gradiend-light)) !important;
}
.neoCheckbox:checked.is-checked-bold + label {
font-weight: bold;
}
.neoCheckbox:checked + label:after {
display: inline-block;
width: 0.375rem;
height: 0.6rem;
top: 0.35rem;
left: 0.55rem;
transform: translateY(0rem) rotate(45deg);
border-width: 0.1rem;
border-top-width: 0.1rem;
border-left-width: 0.1rem;
border-style: solid;
border-top-style: solid;
border-left-style: solid;
border-color: var(--text-color);
border-top: 0;
border-left: 0;
position: absolute;
content: "";
}
hr.neoSeparatorFlat {
height: 10px;
border: none;
border-radius: 20px;
box-shadow: -2px -2px 4px var(--light-shadow), 2px 2px 4px var(--dark-shadow);
background: var(--background); }
background: var(--background);
}
hr.neoSeparatorPressed {
height: 10px;
border: none;
border-radius: 20px;
box-shadow: inset 2px 2px 4px var(--dark-shadow), inset -2px -2px 4px var(--light-shadow);
background: linear-gradient(145deg, var(--primary-gradiend-dark), var(--primary-gradiend-light)); }
background: linear-gradient(145deg, var(--primary-gradiend-dark), var(--primary-gradiend-light));
}
input.neoRange[type=range] {
height: 30px;
-webkit-appearance: none;
width: 100%;
background: transparent; }
input.neoRange[type=range]:focus {
outline: none; }
input.neoRange[type=range]::-webkit-slider-runnable-track {
width: 100%;
height: 20px;
cursor: pointer;
animate: 0.2s;
border-radius: 20px;
box-shadow: inset 2px 2px 4px var(--dark-shadow), inset -2px -2px 4px var(--light-shadow);
background: linear-gradient(90deg, #fa9e9e, #faad9e, #fabd9e, #facc9e, #fadb9e, #faeb9e, #fafa9e, #ebfa9e, #dbfa9e, #ccfa9e, #bdfa9e, #adfa9e, #9efa9e, #9efaad, #9efabd, #9efacc, #9efadb, #9efaeb, #9efafa, #9eebfa, #9edbfa, #9eccfa, #9ebdfa, #9eadfa, #9e9efa, #ad9efa, #bd9efa, #cc9efa, #db9efa, #eb9efa, #fa9efa, #fa9eeb, #fa9edb, #fa9ecc, #fa9ebd, #fa9ead, #fa9ea0) !important; }
input.neoRange[type=range]::-webkit-slider-thumb {
border: none;
height: 26px;
width: 26px;
border-radius: 20px;
box-shadow: 2px 2px 4px var(--dark-shadow), -2px -2px 4px var(--light-shadow);
background: linear-gradient(145deg, var(--primary-gradiend-light), var(--primary-gradiend-dark)) !important;
cursor: pointer;
-webkit-appearance: none;
margin-top: -3px; }
input.neoRange[type=range]:focus::-webkit-slider-runnable-track {
background: linear-gradient(90deg, #fa9e9e, #faad9e, #fabd9e, #facc9e, #fadb9e, #faeb9e, #fafa9e, #ebfa9e, #dbfa9e, #ccfa9e, #bdfa9e, #adfa9e, #9efa9e, #9efaad, #9efabd, #9efacc, #9efadb, #9efaeb, #9efafa, #9eebfa, #9edbfa, #9eccfa, #9ebdfa, #9eadfa, #9e9efa, #ad9efa, #bd9efa, #cc9efa, #db9efa, #eb9efa, #fa9efa, #fa9eeb, #fa9edb, #fa9ecc, #fa9ebd, #fa9ead, #fa9ea0) !important; }
input.neoRange[type=range]::-moz-range-track {
width: 100%;
height: 20px;
cursor: pointer;
border-radius: 20px;
box-shadow: inset 2px 2px 4px var(--dark-shadow), inset -2px -2px 4px var(--light-shadow);
background: linear-gradient(90deg, #fa9e9e, #faad9e, #fabd9e, #facc9e, #fadb9e, #faeb9e, #fafa9e, #ebfa9e, #dbfa9e, #ccfa9e, #bdfa9e, #adfa9e, #9efa9e, #9efaad, #9efabd, #9efacc, #9efadb, #9efaeb, #9efafa, #9eebfa, #9edbfa, #9eccfa, #9ebdfa, #9eadfa, #9e9efa, #ad9efa, #bd9efa, #cc9efa, #db9efa, #eb9efa, #fa9efa, #fa9eeb, #fa9edb, #fa9ecc, #fa9ebd, #fa9ead, #fa9ea0) !important;
border: none; }
input.neoRange[type=range]::-moz-range-thumb {
border: none;
height: 26px;
width: 26px;
border-radius: 20px;
box-shadow: 2px 2px 4px var(--dark-shadow), -2px -2px 4px var(--light-shadow);
background: linear-gradient(145deg, var(--primary-gradiend-light), var(--primary-gradiend-dark)) !important;
cursor: pointer; }
background: transparent;
}
input.neoRange[type=range]:focus {
outline: none;
}
input.neoRange[type=range]::-webkit-slider-runnable-track {
width: 100%;
height: 20px;
cursor: pointer;
animate: 0.2s;
border-radius: 20px;
box-shadow: inset 2px 2px 4px var(--dark-shadow), inset -2px -2px 4px var(--light-shadow);
background: linear-gradient(90deg, hsl(0deg, 90%, 80%), hsl(10deg, 90%, 80%), hsl(20deg, 90%, 80%), hsl(30deg, 90%, 80%), hsl(40deg, 90%, 80%), hsl(50deg, 90%, 80%), hsl(60deg, 90%, 80%), hsl(70deg, 90%, 80%), hsl(80deg, 90%, 80%), hsl(90deg, 90%, 80%), hsl(100deg, 90%, 80%), hsl(110deg, 90%, 80%), hsl(120deg, 90%, 80%), hsl(130deg, 90%, 80%), hsl(140deg, 90%, 80%), hsl(150deg, 90%, 80%), hsl(160deg, 90%, 80%), hsl(170deg, 90%, 80%), hsl(180deg, 90%, 80%), hsl(190deg, 90%, 80%), hsl(200deg, 90%, 80%), hsl(210deg, 90%, 80%), hsl(220deg, 90%, 80%), hsl(230deg, 90%, 80%), hsl(240deg, 90%, 80%), hsl(250deg, 90%, 80%), hsl(260deg, 90%, 80%), hsl(270deg, 90%, 80%), hsl(280deg, 90%, 80%), hsl(290deg, 90%, 80%), hsl(300deg, 90%, 80%), hsl(310deg, 90%, 80%), hsl(320deg, 90%, 80%), hsl(330deg, 90%, 80%), hsl(340deg, 90%, 80%), hsl(350deg, 90%, 80%), hsl(359deg, 90%, 80%)) !important;
}
input.neoRange[type=range]::-webkit-slider-thumb {
border: none;
height: 26px;
width: 26px;
border-radius: 20px;
box-shadow: 2px 2px 4px var(--dark-shadow), -2px -2px 4px var(--light-shadow);
background: linear-gradient(145deg, var(--primary-gradiend-light), var(--primary-gradiend-dark)) !important;
cursor: pointer;
-webkit-appearance: none;
margin-top: -3px;
}
input.neoRange[type=range]:focus::-webkit-slider-runnable-track {
background: linear-gradient(90deg, hsl(0deg, 90%, 80%), hsl(10deg, 90%, 80%), hsl(20deg, 90%, 80%), hsl(30deg, 90%, 80%), hsl(40deg, 90%, 80%), hsl(50deg, 90%, 80%), hsl(60deg, 90%, 80%), hsl(70deg, 90%, 80%), hsl(80deg, 90%, 80%), hsl(90deg, 90%, 80%), hsl(100deg, 90%, 80%), hsl(110deg, 90%, 80%), hsl(120deg, 90%, 80%), hsl(130deg, 90%, 80%), hsl(140deg, 90%, 80%), hsl(150deg, 90%, 80%), hsl(160deg, 90%, 80%), hsl(170deg, 90%, 80%), hsl(180deg, 90%, 80%), hsl(190deg, 90%, 80%), hsl(200deg, 90%, 80%), hsl(210deg, 90%, 80%), hsl(220deg, 90%, 80%), hsl(230deg, 90%, 80%), hsl(240deg, 90%, 80%), hsl(250deg, 90%, 80%), hsl(260deg, 90%, 80%), hsl(270deg, 90%, 80%), hsl(280deg, 90%, 80%), hsl(290deg, 90%, 80%), hsl(300deg, 90%, 80%), hsl(310deg, 90%, 80%), hsl(320deg, 90%, 80%), hsl(330deg, 90%, 80%), hsl(340deg, 90%, 80%), hsl(350deg, 90%, 80%), hsl(359deg, 90%, 80%)) !important;
}
input.neoRange[type=range]::-moz-range-track {
width: 100%;
height: 20px;
cursor: pointer;
border-radius: 20px;
box-shadow: inset 2px 2px 4px var(--dark-shadow), inset -2px -2px 4px var(--light-shadow);
background: linear-gradient(90deg, hsl(0deg, 90%, 80%), hsl(10deg, 90%, 80%), hsl(20deg, 90%, 80%), hsl(30deg, 90%, 80%), hsl(40deg, 90%, 80%), hsl(50deg, 90%, 80%), hsl(60deg, 90%, 80%), hsl(70deg, 90%, 80%), hsl(80deg, 90%, 80%), hsl(90deg, 90%, 80%), hsl(100deg, 90%, 80%), hsl(110deg, 90%, 80%), hsl(120deg, 90%, 80%), hsl(130deg, 90%, 80%), hsl(140deg, 90%, 80%), hsl(150deg, 90%, 80%), hsl(160deg, 90%, 80%), hsl(170deg, 90%, 80%), hsl(180deg, 90%, 80%), hsl(190deg, 90%, 80%), hsl(200deg, 90%, 80%), hsl(210deg, 90%, 80%), hsl(220deg, 90%, 80%), hsl(230deg, 90%, 80%), hsl(240deg, 90%, 80%), hsl(250deg, 90%, 80%), hsl(260deg, 90%, 80%), hsl(270deg, 90%, 80%), hsl(280deg, 90%, 80%), hsl(290deg, 90%, 80%), hsl(300deg, 90%, 80%), hsl(310deg, 90%, 80%), hsl(320deg, 90%, 80%), hsl(330deg, 90%, 80%), hsl(340deg, 90%, 80%), hsl(350deg, 90%, 80%), hsl(359deg, 90%, 80%)) !important;
border: none;
}
input.neoRange[type=range]::-moz-range-thumb {
border: none;
height: 26px;
width: 26px;
border-radius: 20px;
box-shadow: 2px 2px 4px var(--dark-shadow), -2px -2px 4px var(--light-shadow);
background: linear-gradient(145deg, var(--primary-gradiend-light), var(--primary-gradiend-dark)) !important;
cursor: pointer;
}
body {
color: var(--text-color);
background-color: var(--background); }
background-color: var(--background);
}
.background {
background-color: var(--background); }
background-color: var(--background);
}
details > summary::-webkit-details-marker {
color: var(--text-color); }
color: var(--text-color);
}
:focus-visible {
outline: none; }
outline: none;
}
*, ::after, ::before {
scrollbar-color: inherit;
scrollbar-width: inherit; }
scrollbar-width: inherit;
}
::-webkit-scrollbar {
width: 8px; }
width: 8px;
}
::-webkit-scrollbar-button {
width: 8px;
height: 5px; }
height: 5px;
}
::-webkit-scrollbar-track {
background: transparent;
border: thin solid transparent;
box-shadow: none;
border-radius: 10px; }
border-radius: 10px;
}
::-webkit-scrollbar-thumb {
background: var(--primary-color-dark);
border: thin solid transparent;
border-radius: 10px; }
border-radius: 10px;
}
::-webkit-scrollbar-thumb:hover {
background: var(--primary-color-dark); }
background: var(--primary-color-dark);
}
::-moz-selection {
/* Code for Firefox */
::-moz-selection { /* Code for Firefox */
color: var(--primary-color);
background: var(--primary-color-dark); }
background: var(--primary-color-dark);
}
::selection {
color: var(--primary-color);
background: var(--primary-color-dark); }
background: var(--primary-color-dark);
}
.flex.flex-col-reverse > div:first-child {
margin-top: 1rem; }
margin-top: 1rem;
}
.loadAnimation span {
animation-name: blink;
animation-duration: 1.4s;
animation-iteration-count: infinite;
animation-fill-mode: both; }
animation-fill-mode: both;
}
.loadAnimation span:nth-child(1) {
animation-delay: .4s; }
animation-delay: 0.4s;
}
.loadAnimation span:nth-child(2) {
animation-delay: .3s; }
animation-delay: 0.3s;
}
.loadAnimation span:nth-child(3) {
animation-delay: .2s; }
animation-delay: 0.2s;
}
.loadAnimation span:nth-child(4) {
animation-delay: .2s; }
animation-delay: 0.2s;
}
.loadAnimation span:nth-child(5) {
animation-delay: .3s; }
animation-delay: 0.3s;
}
.loadAnimation span:nth-child(6) {
animation-delay: .4s; }
animation-delay: 0.4s;
}

1
wwwroot/css/main.min.css vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

@ -6,7 +6,6 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<title>Index</title>
<base href="/" />
<link href="_content/Blazored.Modal/blazored-modal.css" rel="stylesheet"/>
<link href="css/style.min.css" rel="stylesheet" />
<link href="manifest.json" rel="manifest" />
<link rel="apple-touch-icon" sizes="512x512" href="imgs/icon-512.png" />
@ -20,8 +19,6 @@
<script src="_framework/blazor.webassembly.js"></script>
<script src="_content/Microsoft.AspNetCore.Components.WebAssembly.Authentication/AuthenticationService.js"></script>
<script src="_content/Append.Blazor.Notifications/scripts.js" type="module"></script>
<script src="_content/Blazored.Modal/blazored.modal.js"></script>
<script src="rxjs.7.4.0.min.js"></script>
<script src="_content/DnetIndexedDb/dnet-indexeddb.js"></script>
<script src="_content/Toolbelt.Blazor.HeadElement.Services/script.min.js"></script>

3009
wwwroot/vendor/bulma.css vendored

File diff suppressed because it is too large Load Diff

2
wwwroot/vendor/bulma.min.css vendored Normal file

File diff suppressed because one or more lines are too long