Basics Done

This commit is contained in:
2026-04-13 15:08:49 +05:00
parent 9bef5813ae
commit 06ec22704b
75 changed files with 5036 additions and 2733 deletions
@@ -0,0 +1,37 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<base href="/" />
<script>
// Synchronous dark-mode bootstrap — runs before first paint to prevent FOUC.
// Must stay in sync with the 'theme' localStorage key used by darkmode.js.
(function () {
try {
if (localStorage.getItem('theme') === 'dark')
document.documentElement.classList.add('dark');
} catch (e) { }
})();
</script>
<link rel="stylesheet" href="_content/Enciphered.Blazor.UIComponents/css/app.css" />
<link rel="stylesheet" href="@Assets["css/app.css"]" />
<link rel="stylesheet" href="@Assets["Enciphered.Blazor.UIComponents.Demo.styles.css"]" />
<ImportMap />
<link rel="icon" type="image/svg+xml" href="enci_white.svg" />
<HeadOutlet />
</head>
<body class="min-h-svh antialiased bg-background text-foreground">
<Routes />
<script src="_framework/blazor.web.js"></script>
<script type="module">
import { init as initDarkMode } from '/_content/Enciphered.Blazor.UIComponents/js/darkmode.js';
import { init as initSidebar } from '/_content/Enciphered.Blazor.UIComponents/js/sidebar.js';
initDarkMode();
initSidebar();
</script>
</body>
</html>
@@ -0,0 +1,87 @@
@inherits LayoutComponentBase
@using Enciphered.Blazor.UIComponents
<SidebarProvider DefaultOpen="true">
<Sidebar>
<SidebarHeader>
<div class="flex items-center gap-2 px-1 py-1.5 overflow-hidden">
<div class="flex shrink-0 aspect-square size-8 items-center justify-center">
<img src="enci_white.svg" alt="Enciphered" class="size-5 hidden dark:block" />
<img src="enci.svg" alt="Enciphered" class="size-5 block dark:hidden" />
</div>
<span class="truncate font-semibold text-sm group-data-[state=collapsed]:group-data-[mobile=false]:hidden">Enciphered UI</span>
</div>
</SidebarHeader>
<SidebarContent>
<SidebarGroup>
<SidebarGroupLabel Label="Navigation" />
<SidebarGroupContent>
<SidebarMenuItem Href="/" Tooltip="Home">
<Icon>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24"
fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="m3 9 9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" />
<polyline points="9 22 9 12 15 12 15 22" />
</svg>
</Icon>
<ChildContent>Home</ChildContent>
</SidebarMenuItem>
<SidebarMenuItem Href="/counter" Tooltip="Counter">
<Icon>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24"
fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<rect width="18" height="18" x="3" y="3" rx="2" ry="2" />
<line x1="12" x2="12" y1="8" y2="16" />
<line x1="8" x2="16" y1="12" y2="12" />
</svg>
</Icon>
<ChildContent>Counter</ChildContent>
</SidebarMenuItem>
<SidebarMenuItem Href="/weather" Tooltip="Weather">
<Icon>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24"
fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M17.5 19H9a7 7 0 1 1 6.71-9h1.79a4.5 4.5 0 1 1 0 9Z" />
</svg>
</Icon>
<ChildContent>Weather</ChildContent>
</SidebarMenuItem>
<SidebarMenuItem Href="/forms" Tooltip="Forms">
<Icon>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24"
fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M12 3H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7" />
<path d="M18.375 2.625a1 1 0 0 1 3 3l-9.013 9.014a2 2 0 0 1-.853.505l-2.873.84a.5.5 0 0 1-.62-.62l.84-2.873a2 2 0 0 1 .506-.852z" />
</svg>
</Icon>
<ChildContent>Forms</ChildContent>
</SidebarMenuItem>
</SidebarGroupContent>
</SidebarGroup>
</SidebarContent>
<SidebarFooter>
<div class="group-data-[state=collapsed]:group-data-[mobile=false]:hidden">
<SidebarSeparator />
<div class="px-3 py-2 text-xs text-sidebar-foreground/50 truncate">
&copy; 2026 Enciphered
</div>
</div>
</SidebarFooter>
</Sidebar>
<SidebarInset>
<header class="flex h-14 items-center gap-2 border-b border-border px-4">
<SidebarTrigger Class="md:hidden" />
<h1 class="text-sm font-medium">Demo App</h1>
<div class="ml-auto">
<ThemeToggle />
</div>
</header>
<div class="flex-1 p-4 md:p-6">
@Body
</div>
</SidebarInset>
</SidebarProvider>
@@ -0,0 +1,19 @@
@page "/counter"
@rendermode InteractiveServer
<PageTitle>Counter</PageTitle>
<h1>Counter</h1>
<p role="status">Current count: @currentCount</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
@code {
private int currentCount = 0;
private void IncrementCount()
{
currentCount++;
}
}
@@ -0,0 +1,36 @@
@page "/Error"
@using System.Diagnostics
<PageTitle>Error</PageTitle>
<h1 class="text-danger">Error.</h1>
<h2 class="text-danger">An error occurred while processing your request.</h2>
@if (ShowRequestId)
{
<p>
<strong>Request ID:</strong> <code>@RequestId</code>
</p>
}
<h3>Development Mode</h3>
<p>
Swapping to <strong>Development</strong> environment will display more detailed information about the error that occurred.
</p>
<p>
<strong>The Development environment shouldn't be enabled for deployed applications.</strong>
It can result in displaying sensitive information from exceptions to end users.
For local debugging, enable the <strong>Development</strong> environment by setting the <strong>ASPNETCORE_ENVIRONMENT</strong> environment variable to <strong>Development</strong>
and restarting the app.
</p>
@code{
[CascadingParameter]
private HttpContext? HttpContext { get; set; }
private string? RequestId { get; set; }
private bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
protected override void OnInitialized() =>
RequestId = Activity.Current?.Id ?? HttpContext?.TraceIdentifier;
}
@@ -0,0 +1,126 @@
@page "/forms"
@rendermode InteractiveServer
@using System.ComponentModel.DataAnnotations
<PageTitle>Forms</PageTitle>
<div class="space-y-6 max-w-lg">
<div>
<h1 class="text-3xl font-bold tracking-tight">Forms Demo</h1>
<p class="text-muted-foreground">All input components with DataAnnotations validation.</p>
</div>
<EditForm EditContext="_editContext" OnSubmit="HandleSubmit" FormName="demo-form">
<DataAnnotationsValidator />
<div class="space-y-4">
<FormField Label="Full Name" For="name" Error="@GetError(nameof(Model.Name))">
<TextInput Id="name" @bind-Value="Model.Name" Placeholder="Jane Doe" data-testid="input-name" />
</FormField>
<FormField Label="Email" For="email" Error="@GetError(nameof(Model.Email))">
<TextInput Id="email" Type="email" @bind-Value="Model.Email" Placeholder="jane@example.com" data-testid="input-email" />
</FormField>
<FormField Label="Password" For="password" Error="@GetError(nameof(Model.Password))">
<TextInput Id="password" Type="password" @bind-Value="Model.Password" Placeholder="••••••••" data-testid="input-password" />
</FormField>
<FormField Label="Age" For="age" Error="@GetError(nameof(Model.Age))">
<NumberInput Id="age" @bind-Value="Model.Age" Placeholder="25" Min="0" Max="150" data-testid="input-age" />
</FormField>
<FormField Label="Birth Date" For="birthdate" Error="@GetError(nameof(Model.BirthDate))">
<DateInput Id="birthdate" @bind-Value="Model.BirthDate" data-testid="input-birthdate" />
</FormField>
<FormField Label="Preferred Time" For="preferredtime" Error="@GetError(nameof(Model.PreferredTime))">
<TimeInput Id="preferredtime" @bind-Value="Model.PreferredTime" data-testid="input-time" />
</FormField>
<FormField Label="Appointment" For="appointment" Error="@GetError(nameof(Model.Appointment))">
<DateTimeInput Id="appointment" @bind-Value="Model.Appointment" data-testid="input-appointment" />
</FormField>
<div class="flex gap-2 pt-2">
<Button Type="submit" data-testid="btn-submit">Submit</Button>
<Button Variant="@ButtonVariant.Outline" OnClick="HandleReset" data-testid="btn-reset">Reset</Button>
<Button Variant="@ButtonVariant.Destructive" Disabled="true" data-testid="btn-disabled">Disabled</Button>
</div>
</div>
</EditForm>
@if (_submitted)
{
<div data-testid="success-message"
class="rounded-md border border-input bg-card p-4 text-sm text-card-foreground">
<p class="font-medium">✓ Form submitted successfully</p>
<p class="text-muted-foreground mt-1">Name: @_submittedName</p>
</div>
}
</div>
@code {
private FormModel Model { get; set; } = new();
private EditContext _editContext = null!;
private bool _submitted;
private string _submittedName = "";
protected override void OnInitialized()
{
_editContext = new EditContext(Model);
}
private string? GetError(string fieldName)
{
var field = _editContext.Field(fieldName);
var messages = _editContext.GetValidationMessages(field);
return messages.FirstOrDefault();
}
private void HandleSubmit()
{
_submitted = false;
if (!_editContext.Validate())
return;
_submittedName = Model.Name!;
_submitted = true;
}
private void HandleReset()
{
Model = new();
_submitted = false;
_editContext = new EditContext(Model);
}
public class FormModel
{
[Required(ErrorMessage = "Name is required.")]
[StringLength(100, MinimumLength = 2, ErrorMessage = "Name must be 2100 characters.")]
public string? Name { get; set; }
[Required(ErrorMessage = "Email is required.")]
[EmailAddress(ErrorMessage = "Invalid email address.")]
public string? Email { get; set; }
[Required(ErrorMessage = "Password is required.")]
[StringLength(64, MinimumLength = 8, ErrorMessage = "Password must be 864 characters.")]
public string? Password { get; set; }
[Required(ErrorMessage = "Age is required.")]
[Range(1, 150, ErrorMessage = "Age must be between 1 and 150.")]
public double? Age { get; set; }
[Required(ErrorMessage = "Birth date is required.")]
public DateOnly? BirthDate { get; set; }
[Required(ErrorMessage = "Preferred time is required.")]
public TimeOnly? PreferredTime { get; set; }
[Required(ErrorMessage = "Appointment is required.")]
public DateTime? Appointment { get; set; }
}
}
@@ -0,0 +1,8 @@
@page "/"
<PageTitle>Home</PageTitle>
<div class="space-y-4">
<h1 class="text-3xl font-bold tracking-tight">Welcome</h1>
<p class="text-muted-foreground">This is the Enciphered Blazor UI Components demo app.</p>
</div>
@@ -0,0 +1,64 @@
@page "/weather"
@attribute [StreamRendering]
<PageTitle>Weather</PageTitle>
<h1>Weather</h1>
<p>This component demonstrates showing data.</p>
@if (forecasts == null)
{
<p><em>Loading...</em></p>
}
else
{
<table class="table">
<thead>
<tr>
<th>Date</th>
<th aria-label="Temperature in Celsius">Temp. (C)</th>
<th aria-label="Temperature in Farenheit">Temp. (F)</th>
<th>Summary</th>
</tr>
</thead>
<tbody>
@foreach (var forecast in forecasts)
{
<tr>
<td>@forecast.Date.ToShortDateString()</td>
<td>@forecast.TemperatureC</td>
<td>@forecast.TemperatureF</td>
<td>@forecast.Summary</td>
</tr>
}
</tbody>
</table>
}
@code {
private WeatherForecast[]? forecasts;
protected override async Task OnInitializedAsync()
{
// Simulate asynchronous loading to demonstrate streaming rendering
await Task.Delay(500);
var startDate = DateOnly.FromDateTime(DateTime.Now);
var summaries = new[] { "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" };
forecasts = Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = startDate.AddDays(index),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = summaries[Random.Shared.Next(summaries.Length)]
}).ToArray();
}
private class WeatherForecast
{
public DateOnly Date { get; set; }
public int TemperatureC { get; set; }
public string? Summary { get; set; }
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
}
}
@@ -0,0 +1,5 @@
<Router AppAssembly="typeof(Program).Assembly" AdditionalAssemblies="new[] { typeof(Enciphered.Blazor.UIComponents.SidebarProvider).Assembly }">
<Found Context="routeData">
<RouteView RouteData="routeData" DefaultLayout="typeof(Layout.MainLayout)" />
</Found>
</Router>
@@ -0,0 +1,11 @@
@using System.Net.Http
@using System.Net.Http.Json
@using Microsoft.AspNetCore.Components.Forms
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.Web
@using static Microsoft.AspNetCore.Components.Web.RenderMode
@using Microsoft.AspNetCore.Components.Web.Virtualization
@using Microsoft.JSInterop
@using Enciphered.Blazor.UIComponents.Demo
@using Enciphered.Blazor.UIComponents.Demo.Components
@using Enciphered.Blazor.UIComponents
@@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<ItemGroup>
<ProjectReference Include="..\Enciphered.Blazor.UIComponents\Enciphered.Blazor.UIComponents.csproj" />
</ItemGroup>
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<Target Name="TailwindBuild" BeforeTargets="Build">
<Exec Command="npx @tailwindcss/cli -i Styles/app.css -o wwwroot/css/app.css --minify" />
</Target>
</Project>
@@ -0,0 +1,29 @@
using Enciphered.Blazor.UIComponents.Demo.Components;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddRazorComponents()
.AddInteractiveServerComponents();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error", createScopeForErrors: true);
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseAntiforgery();
app.MapStaticAssets();
app.MapRazorComponents<App>()
.AddInteractiveServerRenderMode()
.AddAdditionalAssemblies(typeof(Enciphered.Blazor.UIComponents.SidebarProvider).Assembly);
app.Run();
@@ -0,0 +1,23 @@
{
"$schema": "https://json.schemastore.org/launchsettings.json",
"profiles": {
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "http://localhost:5146",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"https": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "https://localhost:7065;http://localhost:5146",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
@@ -0,0 +1,160 @@
@import "tailwindcss";
@custom-variant dark (&:where(.dark, .dark *));
/*
* shadcn/ui design tokens.
* These must be defined in every project that uses Tailwind classes with
* the Enciphered.Blazor.UIComponents design system. The library ships a
* pre-built CSS (via _content/.../css/app.css) that covers all component
* classes, but if your own Razor files use token-based utilities like
* bg-background, text-foreground, etc., you need these tokens in your
* own Tailwind source file.
*/
/* ---------- light tokens (neutral) ---------- */
:root {
--background: oklch(1 0 0);
--foreground: oklch(0.145 0 0);
--card: oklch(1 0 0);
--card-foreground: oklch(0.145 0 0);
--popover: oklch(1 0 0);
--popover-foreground: oklch(0.145 0 0);
--primary: oklch(0.205 0 0);
--primary-foreground: oklch(0.985 0 0);
--secondary: oklch(0.97 0 0);
--secondary-foreground: oklch(0.205 0 0);
--muted: oklch(0.97 0 0);
--muted-foreground: oklch(0.556 0 0);
--accent: oklch(0.97 0 0);
--accent-foreground: oklch(0.205 0 0);
--destructive: oklch(0.577 0.245 27.325);
--destructive-foreground: oklch(0.985 0 0);
--border-color: oklch(0.922 0 0);
--input: oklch(0.922 0 0);
--ring: oklch(0.708 0 0);
--radius: 0.625rem;
--sidebar-background: oklch(0.985 0 0);
--sidebar-foreground: oklch(0.145 0 0);
--sidebar-primary: oklch(0.205 0 0);
--sidebar-primary-foreground: oklch(0.985 0 0);
--sidebar-accent: oklch(0.97 0 0);
--sidebar-accent-foreground: oklch(0.205 0 0);
--sidebar-border: oklch(0.922 0 0);
--sidebar-ring: oklch(0.708 0 0);
}
/* ---------- dark tokens (neutral) ---------- */
.dark {
--background: oklch(0.145 0 0);
--foreground: oklch(0.985 0 0);
--card: oklch(0.145 0 0);
--card-foreground: oklch(0.985 0 0);
--popover: oklch(0.145 0 0);
--popover-foreground: oklch(0.985 0 0);
--primary: oklch(0.985 0 0);
--primary-foreground: oklch(0.205 0 0);
--secondary: oklch(0.269 0 0);
--secondary-foreground: oklch(0.985 0 0);
--muted: oklch(0.269 0 0);
--muted-foreground: oklch(0.708 0 0);
--accent: oklch(0.269 0 0);
--accent-foreground: oklch(0.985 0 0);
--destructive: oklch(0.577 0.245 27.325);
--destructive-foreground: oklch(0.985 0 0);
--border-color: oklch(0.269 0 0);
--input: oklch(0.269 0 0);
--ring: oklch(0.439 0 0);
--sidebar-background: oklch(0.205 0 0);
--sidebar-foreground: oklch(0.985 0 0);
--sidebar-primary: oklch(0.985 0 0);
--sidebar-primary-foreground: oklch(0.205 0 0);
--sidebar-accent: oklch(0.269 0 0);
--sidebar-accent-foreground: oklch(0.985 0 0);
--sidebar-border: oklch(0.269 0 0);
--sidebar-ring: oklch(0.556 0 0);
}
/* ---------- Map CSS vars → Tailwind theme ---------- */
@theme {
--color-background: var(--background);
--color-foreground: var(--foreground);
--color-card: var(--card);
--color-card-foreground: var(--card-foreground);
--color-popover: var(--popover);
--color-popover-foreground: var(--popover-foreground);
--color-primary: var(--primary);
--color-primary-foreground: var(--primary-foreground);
--color-secondary: var(--secondary);
--color-secondary-foreground: var(--secondary-foreground);
--color-muted: var(--muted);
--color-muted-foreground: var(--muted-foreground);
--color-accent: var(--accent);
--color-accent-foreground: var(--accent-foreground);
--color-destructive: var(--destructive);
--color-destructive-foreground: var(--destructive-foreground);
--color-border: var(--border-color);
--color-input: var(--input);
--color-ring: var(--ring);
--color-sidebar: var(--sidebar-background);
--color-sidebar-foreground: var(--sidebar-foreground);
--color-sidebar-primary: var(--sidebar-primary);
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
--color-sidebar-accent: var(--sidebar-accent);
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
--color-sidebar-border: var(--sidebar-border);
--color-sidebar-ring: var(--sidebar-ring);
--radius: var(--radius);
--sidebar-width: 16rem;
--sidebar-width-icon: 3rem;
}
/* ---------- Date / Time input native chrome overrides ---------- */
input[type="date"]::-webkit-calendar-picker-indicator,
input[type="time"]::-webkit-calendar-picker-indicator,
input[type="datetime-local"]::-webkit-calendar-picker-indicator {
display: none;
-webkit-appearance: none;
}
input[type="date"]::-webkit-date-and-time-value,
input[type="time"]::-webkit-date-and-time-value,
input[type="datetime-local"]::-webkit-date-and-time-value {
text-align: left;
}
input[type="date"],
input[type="time"],
input[type="datetime-local"] {
color-scheme: light;
}
.dark input[type="date"],
.dark input[type="time"],
.dark input[type="datetime-local"] {
color-scheme: dark;
}
/* ---------- Custom scrollbar for picker columns ---------- */
.scrollbar-thin {
scrollbar-width: thin;
scrollbar-color: var(--muted) transparent;
}
.scrollbar-thin::-webkit-scrollbar {
width: 6px;
}
.scrollbar-thin::-webkit-scrollbar-track {
background: transparent;
border-radius: 3px;
}
.scrollbar-thin::-webkit-scrollbar-thumb {
background-color: var(--muted);
border-radius: 3px;
}
.scrollbar-thin::-webkit-scrollbar-thumb:hover {
background-color: var(--muted-foreground);
}
@@ -0,0 +1,8 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}
@@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 139.27 93.46"><path d="M128.29,55.27c-1.93,1-3.41,6.08-4.63,8.07-4.94-.5-19.7,1.54-23.15-2.21-4.84-6.2-1.65-15.38,2.41-23,55.47,5.25,22.88-51.53-5.14-8.68-1.63-.74-8.13-.29-10-.41-2.7-.14-5.21.51-6.26,3.34l-.56,1.41L71.41,57.21,69.58,33.8c-.25-3.49-1.85-5.24-4.78-5.24-8.21-1-19.41,46.6-26.49,51.72-14.58,13-21.06-11-7.36-17.76,3.3-2.81,11.63-2.46,15.82-4.57,3.46-3.2-.07-8.4-4.82-8H22.4C7.72,50.53,11.68,34.1,17,24.78c55.73,5.19,22.63-51.72-5.31-8.4-2.66.2-8-.77-10,1.46-4.12,4.85-.27,7.73,5.2,6.94-8,14.89-5,35.13,14.46,33.61-23.34,22.92,8.22,51.13,26.77,23.87,3.12-5,11-25.5,14.08-33C63,53.2,63,73.15,65.33,76c2.19,2.62,7.64,1.84,8.86-1.9l.67-1.65,14-34.41c.73.14,3.22.06,4,.08-7.47,14.23-5.8,34,13,33.6h20.39c7.45.64,5.49-6.53,7.73-11.12C136.09,57.39,131.2,53.68,128.29,55.27ZM113.85,23.9c9.51-7.48,15.64,6.48,1.13,5.83h-6.82A23.27,23.27,0,0,1,113.85,23.9ZM28,10.55c9.5-7.48,15.62,6.49,1.12,5.83H22.26A23.13,23.13,0,0,1,28,10.55Z"/><path d="M139.27,46.91a4.87,4.87,0,1,1-1.43-3.46A4.73,4.73,0,0,1,139.27,46.91Z"/></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 139.27 93.46"><defs><style>.a{fill:#fff;}</style></defs><path class="a" d="M128.29,55.27c-1.93,1-3.41,6.08-4.63,8.07-4.94-.5-19.7,1.54-23.15-2.21-4.84-6.2-1.65-15.38,2.41-23,55.47,5.25,22.88-51.53-5.14-8.68-1.63-.74-8.13-.29-10-.41-2.7-.14-5.21.51-6.26,3.34l-.56,1.41L71.41,57.21,69.58,33.8c-.25-3.49-1.85-5.24-4.78-5.24-8.21-1-19.41,46.6-26.49,51.72-14.58,13-21.06-11-7.36-17.76,3.3-2.81,11.63-2.46,15.82-4.57,3.46-3.2-.07-8.4-4.82-8H22.4C7.72,50.53,11.68,34.1,17,24.78c55.73,5.19,22.63-51.72-5.31-8.4-2.66.2-8-.77-10,1.46-4.12,4.85-.27,7.73,5.2,6.94-8,14.89-5,35.13,14.46,33.61-23.34,22.92,8.22,51.13,26.77,23.87,3.12-5,11-25.5,14.08-33C63,53.2,63,73.15,65.33,76c2.19,2.62,7.64,1.84,8.86-1.9l.67-1.65,14-34.41c.73.14,3.22.06,4,.08-7.47,14.23-5.8,34,13,33.6h20.39c7.45.64,5.49-6.53,7.73-11.12C136.09,57.39,131.2,53.68,128.29,55.27ZM113.85,23.9c9.51-7.48,15.64,6.48,1.13,5.83h-6.82A23.27,23.27,0,0,1,113.85,23.9ZM28,10.55c9.5-7.48,15.62,6.49,1.12,5.83H22.26A23.13,23.13,0,0,1,28,10.55Z"/><path class="a" d="M139.27,46.91a4.87,4.87,0,1,1-1.43-3.46A4.73,4.73,0,0,1,139.27,46.91Z"/></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB