Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions BlueBlazor.Docs/Components/Layouts/NavMenu.razor
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@
{
<span class="badge bg-info ms-1 mt-1">Update</span>
}
@if (componentIcons.Where(x => x.Key == item.Key).FirstOrDefault().Value?.IsExperimental == true)
{
<span class="badge text-bg-warning ms-1 mt-1" title="Experimental"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 10240 10240" class="o-collection-icon" width="1em" height="1em" fill="currentColor"><path fill="" d="M7144 5440c139,291 216,616 216,960 0,1237 -1003,2240 -2240,2240 -1237,0 -2240,-1003 -2240,-2240 0,-344 77,-669 216,-960l4048 0zm-1224 320c-442,0 -800,358 -800,800 0,442 358,800 800,800 442,0 800,-358 800,-800 0,-442 -358,-800 -800,-800zm-1280 1600c-265,0 -480,215 -480,480 0,265 215,480 480,480 265,0 480,-215 480,-480 0,-265 -215,-480 -480,-480z"></path><path fill="" d="M6400 3467c1130,493 1920,1621 1920,2933 0,1767 -1433,3200 -3200,3200 -1767,0 -3200,-1433 -3200,-3200 0,-1312 790,-2440 1920,-2933l0 -2187 -320 0c-176,0 -320,-144 -320,-320l0 0c0,-176 144,-320 320,-320l640 0c176,0 320,144 320,320l0 2925 -384 168c-932,407 -1536,1327 -1536,2347 0,1414 1146,2560 2560,2560 1414,0 2560,-1146 2560,-2560 0,-1020 -604,-1940 -1536,-2347l-384 -168 0 -2925c0,-176 144,-320 320,-320l640 0c176,0 320,144 320,320l0 0c0,176 -144,320 -320,320l-320 0 0 2187z"></path></svg></span>
}
</AfterLabelContent>
</MenuItem>
}
Expand Down Expand Up @@ -148,6 +152,9 @@
},
{"DialogProvider", new() {
Icon = @<BiSquare />, IsNew = true }
},
{"ThemeGenerator", new() {
Icon = @<BiPalette />, IconForActive = @<BiPaletteFill />, IsExperimental = true }
} };
RenderFragment defaultIcon = @<BiFileCode />;

Expand All @@ -157,5 +164,6 @@
public RenderFragment? IconForActive { get; set; }
public bool IsNew { get; set; } = false;
public bool IsUpdate { get; set; } = false;
public bool IsExperimental { get; set; } = false;
}
}
50 changes: 50 additions & 0 deletions BlueBlazor.Docs/Stories/ThemeGenerator/BasicUsage.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<div data-bs-theme="@_colorMode" class="d-flex flex-column flex-md-row gap-3">
<div>
Select theme info
<div class="list-group">
@foreach (var themeInfo in _themeInfos)
{
<button type="button" class="list-group-item list-group-item-action"
@onclick="() => { _themeInfo = themeInfo; }">
@themeInfo.Name
</button>
}
</div>
</div>

<div class="p-4 rounded border">
<ThemeGenerator OnCompile="HandleCompile" ThemeInfo="@_themeInfo" />
</div>
</div>

<style type="text/css">
@_css
</style>

@code {
private string _css = "";
private string _colorMode = "light";
private ThemeInfo? _themeInfo;
private List<ThemeInfo> _themeInfos = [new()
{
Name = "Just blue",
Variables = new Dictionary<string, string> {
{ "$theme", "blue" }
}
}, new() {
Name = "Valentine v9",
Variables = new Dictionary<string, string> {
{ "$primary", "hsl(0deg 69% 50%)" },
{ "$theme", "hsl(329deg 100% 94%)" },
{ "$form-check-radio-checked-bg-image", "url(\"data:image/svg+xml,%3Csvg%20fill%3D%22%23fff%22%20class%3D%22bi%20bi-suit-heart-fill%22%20viewBox%3D%220%200%2016%2016%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20d%3D%22M4%201c2.21%200%204%201.755%204%203.92C8%202.755%209.79%201%2012%201s4%201.755%204%203.92c0%203.263-3.234%204.414-7.608%209.608a.513.513%200%2001-.784%200C3.234%209.334%200%208.183%200%204.92%200%202.755%201.79%201%204%201z%22%2F%3E%3C%2Fsvg%3E\")" },
{ "$form-check-input-checked-bg-image", "url(\"data:image/svg+xml,%3Csvg%20viewBox%3D%220%200%2020%2020%22%20style%3D%22background%3A%23fff%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Ctext%20y%3D%2215%22%3E%F0%9F%92%98%3C%2Ftext%3E%3C%2Fsvg%3E\")" }
},
CustomStyle = ".blue-layout-header > header {\n background-image: url(data:image/svg+xml;base64,PHN2ZyBmaWxsLXJ1bGU9ImV2ZW5vZGQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIHN0cm9rZS1taXRlcmxpbWl0PSIyIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIHZpZXdCb3g9IjAgMCAxMDkgNjIiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZmlsbD0iaHNsKDMyOWRlZyA2MCUgODYlKSIgZD0iTTkyLjU4NyAyMi4zNzVjNS4yMjYtMi40MzEgMTAuOTU5Ljg3OSAxMi42NDYgNC41NzcgMS42ODcgMy42OTgtLjY3MiA3Ljc4NC01Ljg5OCAxMC4yMTUtMy43NyAxLjkxLTEwLjcgMS45OTMtMTYuMTg0IDEuNTUxLTMuMTI0LTQuNTI4LTYuNTE3LTEwLjU3Mi02Ljc0OC0xNC43OTEtLjUwNy01Ljc0MSAxLjg1Mi05LjgyNyA1Ljg5OC0xMC4yMTUgNC4wNDYtLjM4OCA5Ljc3OSAyLjkyMiAxMC4yODYgOC42NjN6bS02MC4wMDktOC44NjdjLS4zNjMtNS43NTIgNC44MDYtOS44ODcgOC44NjQtMTAuMTEzIDQuMDU5LS4yMjYgNy4wMDYgMy40NTggNy4zNjkgOS4yMS40MDcgNC4yMDctMi4wMzcgMTAuNjkzLTQuNDQ0IDE1LjY0LTUuMzU0IDEuMjYyLTEyLjIxOCAyLjIyMy0xNi4yMzMuOTAzLTUuNTMyLTEuNjE3LTguNDgtNS4zLTcuMzY4LTkuMjEgMS4xMS0zLjkxIDYuMjgtOC4wNDYgMTEuODEyLTYuNDN6bTI0Ljk4MyAyMi44MDRjLjYwMi0zLjgwOCA0LjU4LTUuNzUzIDcuMjYxLTUuMzA5IDIuNjgyLjQ0NSA0LjA2OCAzLjI4IDMuNDY2IDcuMDg2LS4zNDcgMi44MDUtMi44ODggNi42ODItNS4xOCA5LjU2LTMuNjguMDQ0LTguMy0uMzMtMTAuNzI4LTEuNzc4LTMuMzc1LTEuODYxLTQuNzYyLTQuNjk2LTMuNDY2LTcuMDg2IDEuMjk1LTIuMzkgNS4yNzItNC4zMzUgOC42NDctMi40NzN6bS00Mi4zMTYgOS4yNDFjMy40NDUtMS43MjggNy4zNDMuMzcyIDguNTQ0IDIuODEgMS4yIDIuNDQtLjI5NiA1LjIxNy0zLjc0MiA2Ljk0NS0yLjQ4MiAxLjM1MS03LjExNCAxLjU0NC0xMC43ODggMS4zNTdDNy4wOCA1My43IDQuNjk0IDQ5LjcyNiA0LjQ1NiA0Ni45MWMtLjQ1Mi0zLjgyOCAxLjA0NC02LjYwNiAzLjc0MS02Ljk0NSAyLjY5Ny0uMzQgNi41OTUgMS43NiA3LjA0OCA1LjU4OHoiLz48L3N2Zz4=) !important;\n background-color: var(--blue-header-bg);\n}\n\n.blue-status-loading {\n background-color: transparent;\n box-shadow: none;\n}\n\n.spinner-bounce-circle > div::before {\n content: \"❤️\";\n font-size: 64px;\n display: flex;\n width: 100%;\n height: 100%;\n justify-content: center;\n align-items: center;\n}\n\n.spinner-bounce-circle div {\n opacity: 1;\n background-color: transparent;\n animation-name: love-heart;\n animation-duration: 1s;\n}\n\n.spinner-bounce-circle > div:nth-child(2) {\n display: none;\n}\n\n@keyframes love-heart {\n 0% {\n transform: scale(0.5);\n }\n 50% {\n transform: scale(1);\n }\n 100% {\n transform: scale(0.5);\n }\n}\n\n"
}];

private void HandleCompile(Theme theme)
{
_css = theme.Css;
_colorMode = theme.ThemeInfo?.ColorMode ?? "light";
}
}
2 changes: 1 addition & 1 deletion BlueBlazor.Docs/wwwroot/data/pages-data.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"ActionMenu":"components/action-menu","AlertSection":"components/alert-section","Body":"components/body","Button":"components/button","ButtonOrA":"components/button-or-a","Chevron":"components/chevron","DialogOpener":"components/dialog-opener","DialogProvider":"components/dialog-provider","Header":"components/header","HeaderTitle":"components/header-title","Heading":"components/heading","InlineEdit":"components/inline-edit","Intro":"components/intro","Layout":"components/layout","MenuItem":"components/menu-item","ModalDialog":"components/modal-dialog","OffcanvasDialog":"components/offcanvas-dialog","Outside":"components/outside","Page":"components/page","PageScript":"components/page-script","QrCodeGen":"components/qr-code-gen","SidebarMenu":"components/sidebar-menu","SidebarToggler":"components/sidebar-toggler","SimpleLayout":"components/simple-layout","Tab":"components/tab","Tabs":"components/tabs","TextInput":"components/text-input","TotpInput":"components/totp-input","TuiEditor":"components/tui-editor"}
{"ActionMenu":"components/action-menu","AlertSection":"components/alert-section","Body":"components/body","Button":"components/button","ButtonOrA":"components/button-or-a","Chevron":"components/chevron","DialogOpener":"components/dialog-opener","DialogProvider":"components/dialog-provider","Header":"components/header","HeaderTitle":"components/header-title","Heading":"components/heading","InlineEdit":"components/inline-edit","Intro":"components/intro","Layout":"components/layout","MenuItem":"components/menu-item","ModalDialog":"components/modal-dialog","OffcanvasDialog":"components/offcanvas-dialog","Outside":"components/outside","Page":"components/page","PageScript":"components/page-script","QrCodeGen":"components/qr-code-gen","SidebarMenu":"components/sidebar-menu","SidebarToggler":"components/sidebar-toggler","SimpleLayout":"components/simple-layout","Tab":"components/tab","Tabs":"components/tabs","TextInput":"components/text-input","ThemeGenerator":"components/theme-generator","TotpInput":"components/totp-input","TuiEditor":"components/tui-editor"}
4 changes: 2 additions & 2 deletions BlueBlazor/Components/Button.razor
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
@using Microsoft.Extensions.Localization
@namespace BlueBlazor.Components
@inject IStringLocalizer<BlueBlazor.Resources.Phrases> L

<ButtonOrA @attributes="AdditionalAttributes"
Expand All @@ -9,8 +10,7 @@
aria-label="@(LabelHidden ? Label : null)">
@if (Busy || busy)
{
<span class="spinner-border spinner-border-sm me-1 bi" aria-hidden="true"></span>

<span class="spinner-border spinner-border-sm bi me-1" aria-hidden="true"></span>
<span role="status">@L["Loading"]…</span>
}
else
Expand Down
1 change: 1 addition & 0 deletions BlueBlazor/Components/ThemeGenerator.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<themify-appearance-helper-wrapper @ref="_element"></themify-appearance-helper-wrapper>
98 changes: 98 additions & 0 deletions BlueBlazor/Components/ThemeGenerator.razor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace BlueBlazor.Components;

public partial class ThemeGenerator : ComponentBase
{
[Inject]
private IJSRuntime JSRuntime { get; set; } = default!;

[Parameter]
public ThemeInfo? ThemeInfo { get; set; }

[Parameter]
public EventCallback<Theme> OnCompile { get; set; }

private ElementReference _element;
private IJSObjectReference? _module;

protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
await JSRuntime.InvokeAsync<IJSObjectReference>("import", "./_content/BlueBlazor/themify/themify.es.js");
_module = await JSRuntime.InvokeAsync<IJSObjectReference>("import", "./_content/BlueBlazor/Components/ThemeGenerator.razor.js");
await Initialize();
}
}

protected override async Task OnParametersSetAsync()
{
if (_module is not null && ThemeInfo is not null)
{
string? themeInfoJson = JsonSerializer.Serialize(ThemeInfo);

await _module.InvokeVoidAsync("SetThemeInfo", _element, themeInfoJson);
}
}

private async Task Initialize()
{
if (_module is not null)
{
string? themeInfoJson = null;
if (ThemeInfo != null)
{
themeInfoJson = JsonSerializer.Serialize(ThemeInfo);
}

await _module.InvokeVoidAsync("Initialize", _element, DotNetObjectReference.Create(this), themeInfoJson, null, true);
}
}

[JSInvokable]
public async Task InvokeCompile(string detailsJson)
{
Theme? theme = JsonSerializer.Deserialize<Theme>(detailsJson);
await OnCompile.InvokeAsync(theme);
}
}

public class Theme
{
[JsonPropertyName("css")]
public string Css { get; set; } = "";

[JsonPropertyName("themeInfo")]
public ThemeInfo? ThemeInfo { get; set; }
}

public class ThemeInfo
{
[JsonPropertyName("appearance")]
public string Appearance { get; set; } = "";

[JsonPropertyName("blueWebVersion")]
public string BlueWebVersion { get; set; } = "";

[JsonPropertyName("colorMode")]
public string ColorMode { get; set; } = "";

[JsonPropertyName("exportOnlyCssVars")]
public bool ExportOnlyCssVars { get; set; }

[JsonPropertyName("includeNeuScss")]
public bool IncludeNeuScss { get; set; }

[JsonPropertyName("name")]
public string Name { get; set; } = "";

[JsonPropertyName("variables")]
public Dictionary<string, string> Variables { get; set; } = [];

[JsonPropertyName("customStyle")]
public string? CustomStyle { get; set; } = "";
}
15 changes: 15 additions & 0 deletions BlueBlazor/Components/ThemeGenerator.razor.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
window.process = { env: { NODE_ENV: 'development' } };

export function Initialize(element, dotNetHelper, themeInfo = null, blueWebScssSrc = null, applyOnMount = null) {
if (themeInfo) element.themeInfo = JSON.parse(themeInfo)
if (blueWebScssSrc) element.blueWebScssSrc = blueWebScssSrc
if (applyOnMount) element.applyOnMount = applyOnMount

element.addEventListener("compile", ({ detail }) => {
dotNetHelper.invokeMethodAsync("InvokeCompile", JSON.stringify(detail));
})
}

export function SetThemeInfo(element, themeInfo) {
element.themeInfo = JSON.parse(themeInfo)
}
9 changes: 6 additions & 3 deletions BlueBlazor/buildScripts/copyToWwwroot.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@ async function copyDirectory(source, destination) {
}
}

const sourceDir = path.join(__dirname, "..", "node_modules", "blue-web", "dist")
const destinationDir = path.join(__dirname, "..", "wwwroot", "blue-web")
copyDirectory(
path.join(__dirname, "..", "node_modules", "blue-web", "dist"),
path.join(__dirname, "..", "wwwroot", "blue-web"))

copyDirectory(sourceDir, destinationDir)
copyDirectory(
path.join(__dirname, "..", "node_modules", "themify", "dist"),
path.join(__dirname, "..", "wwwroot", "themify"))
Loading