Skip to content

Commit be13040

Browse files
feat(docs/tools): add Material 3 theme creator tool to docs site
Adds a new Material 3 theme creator at /tools/material-theme with a full UI for generating, previewing, and downloading Material Design color schemes. Introduces MaterialThemeConverter.razor, supporting Blazor components, SCSS, and a color picker for custom and NTComponents-extended palettes. Integrates @material/material-color-utilities (npm) and a TypeScript module (theme-creator.ts) for live color scheme generation and preview, bundled via esbuild. Implements logic for six theme variants (light, dark, medium/high contrast), live preview in a scoped container, and ZIP download of all variants. Adds a converter for importing Material Theme Builder CSS, renaming tokens, error handling, and download of converted archives. Comprehensive Playwright integration tests cover theme generation, preview, palette overrides, ZIP download, and CSS conversion. Updates .gitignore, package.json, and package-lock.json for new dependencies and build scripts. Refactors build scripts: adds build-site-assets.mjs for esbuild bundling, updates minify-typescript.mjs to only minify NTComponents sources. Updates MainLayout.razor to link to the new tool. All changes are additive and scoped to the documentation site.
1 parent 2c4156e commit be13040

17 files changed

Lines changed: 2435 additions & 5 deletions

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,7 @@ coverlet.runsettings
414414
/NTComponents/Carousel/NTCarousel.razor.js
415415
/NTComponents/Window/NTWindow.razor.js
416416
/NTComponents.Site/wwwroot/js/docs.js
417+
/NTComponents.Site/wwwroot/js/theme-creator.js
417418
/NTComponents/Accordion/TnTAccordion.razor.js
418419
/NTComponents/Animation/TnTAnimation.razor.js
419420
/NTComponents/Core/TnTExternalClickHandler.razor.js

NTComponents.Site/Layout/MainLayout.razor

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
<NTLayout>
55
<NTNavigationRail AriaLabel="Documentation navigation" OpenByDefault="true" >
66
<NTNavigationRailItem Label="Home" Href="/" Match="NavLinkMatch.All" Icon="MaterialIcon.Home" />
7+
<NTNavigationRailItem Label="Theme creator" Href="/tools/material-theme" Match="NavLinkMatch.All" Icon="MaterialIcon.Palette" />
78
<NTNavigationRailGroup Label="Components" Icon="MaterialIcon.Category" Expanded="true">
89
<NTNavigationRailItem Label="All components" Href="/components" Match="NavLinkMatch.All" Icon="MaterialIcon.Category" />
910
@foreach (var group in Catalog.ComponentGroups) {
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<div class="material-color-picker @(Disabled ? "disabled" : null)" style="@($"--theme-picker-color: {Value}")" data-theme-color-picker>
2+
<label for="@ElementId">
3+
<span class="picker-swatch" aria-hidden="true"></span>
4+
<span class="picker-copy">
5+
<span class="picker-label">@Label</span>
6+
<output class="picker-value" for="@ElementId" data-theme-color-output>@Value.ToUpperInvariant()</output>
7+
</span>
8+
<span class="picker-action" aria-hidden="true">Edit</span>
9+
</label>
10+
<input id="@ElementId"
11+
type="color"
12+
value="@Value"
13+
disabled="@Disabled"
14+
aria-label="@Label"
15+
data-theme-color-key="@ColorKey"
16+
@onchange="HandleChangeAsync" />
17+
</div>
18+
19+
@code {
20+
[Parameter, EditorRequired]
21+
public string ColorKey { get; set; } = string.Empty;
22+
23+
[Parameter]
24+
public bool Disabled { get; set; }
25+
26+
[Parameter, EditorRequired]
27+
public string ElementId { get; set; } = string.Empty;
28+
29+
[Parameter, EditorRequired]
30+
public string Label { get; set; } = string.Empty;
31+
32+
[Parameter, EditorRequired]
33+
public string Value { get; set; } = "#000000";
34+
35+
[Parameter]
36+
public EventCallback<string> ValueChanged { get; set; }
37+
38+
private Task HandleChangeAsync(ChangeEventArgs args) => ValueChanged.InvokeAsync(args.Value?.ToString() ?? Value);
39+
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
.material-color-picker {
2+
border: 1px solid var(--tnt-color-outline);
3+
border-radius: var(--tnt-corner-radius-medium);
4+
min-height: 64px;
5+
overflow: hidden;
6+
position: relative;
7+
transition: background-color 120ms ease, border-color 120ms ease;
8+
9+
&:hover {
10+
background: color-mix(in srgb, var(--tnt-color-on-surface) 8%, transparent);
11+
border-color: var(--tnt-color-on-surface);
12+
}
13+
14+
&:focus-within {
15+
border-color: var(--tnt-color-primary);
16+
box-shadow: inset 0 0 0 1px var(--tnt-color-primary);
17+
}
18+
19+
label {
20+
align-items: center;
21+
color: var(--tnt-color-on-surface);
22+
display: grid;
23+
gap: 12px;
24+
grid-template-columns: 40px minmax(0, 1fr) auto;
25+
min-height: 64px;
26+
padding: 8px 16px;
27+
}
28+
29+
.picker-swatch {
30+
background: var(--theme-picker-color);
31+
border: 1px solid color-mix(in srgb, var(--tnt-color-on-surface) 24%, transparent);
32+
border-radius: var(--tnt-corner-radius-full);
33+
height: 40px;
34+
width: 40px;
35+
}
36+
37+
.picker-copy {
38+
display: grid;
39+
gap: 2px;
40+
min-width: 0;
41+
}
42+
43+
.picker-label {
44+
font-size: 12px;
45+
font-weight: 600;
46+
letter-spacing: 0.4px;
47+
}
48+
49+
.picker-value {
50+
color: var(--tnt-color-on-surface-variant);
51+
font-family: var(--tnt-typography-font-family-code, monospace);
52+
font-size: 14px;
53+
}
54+
55+
.picker-action {
56+
color: var(--tnt-color-primary);
57+
font-size: 12px;
58+
font-weight: 700;
59+
text-transform: uppercase;
60+
}
61+
62+
input {
63+
cursor: pointer;
64+
inset: 0;
65+
opacity: 0;
66+
position: absolute;
67+
width: 100%;
68+
}
69+
70+
&.disabled {
71+
opacity: 0.48;
72+
73+
input {
74+
cursor: not-allowed;
75+
}
76+
}
77+
}

0 commit comments

Comments
 (0)